2016-07-22 7 views
1

私はmethod(int id)の中にクリティカルセクションを持つシナリオを持っています。複数のスレッドが異なるIDを使ってこのメソッドを呼び出すとき、これらの複数のスレッドにクリティカルセクションへのアクセス権を与えることができますが、id(メソッドparam) "x"を持つ新しいスレッドが既に同じIDを持つスレッドもう一方のスレッドは入力できません。異なるIDを持つ複数のスレッドがクリティカルセクションに入ることを可能にするマルチスレッド

これ以上の情報が必要な場合はお知らせください。

+1

はい、コードが書かれたシナリオに役立つだろう。 –

+0

[組み込みのロックと同期](https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html) –

+0

@AndyTurnerは、最初のロックオブジェクトを占有しても、すべてのスレッドをブロックしませんか? – Memfisto

答えて

1

私は、リストにIDを格納し、スレッドのIDがすでにリストの中に入っているかどうかをチェックするという簡単な解決策があると思います。スレッドがクリティカルコードを完成させたら、そのIDをリストから削除します。

通常、クリティカルセクションへのアクセスを防止するために、同期ブロックを使用しますが、「複製」スレッドへのアクセスのみをブロックする必要があるため、そうすることはできません。

+1

そのリストを変更するには、グローバル・ロックが必要であることに言及する必要があります。 idが解放されるのを待つことも簡単な作業ではありません。 –

+0

@ Memfistoこれはシンプルだが間違った解決策です。複数のスレッドが同じIDを処理しないようにするには、同期が必要です。 –

+0

どうすればこのアプローチが可能になりますか?@memfistoは指定されていますが、別の方法で処理されます。 入力の設定 = new HashSet(); ボイドdoSmoething(){ 同期(本){ 一方(inputs.contains(I)){ 待機();} inputs.add(I)。 } //クリティカルセクションコード 同期(this){ inputs.remove(i); notofyAll(); } } –

3

あなたがクリティカルセクションを含むクラスにプライベートConcurrentHashMap<Integer, Object>、使用、およびIDごとの監視対象を保持することができます。これは、アトミックマップにオブジェクトを挿入し、その後

private final ConcurrentHashMap<Integer, Object> locks = new ConcurrentHashMap<>(); 

synchronized (locks.computeIfAbsent(id, id -> new Object())) { 
    // Critical section. 
} 

を新しいIDに遭遇したときにそれを返します。そのブロックは任意のオブジェクト上で同期される。

同じIDが検出されると、以前に作成されたオブジェクトが返されます。これは、ブロック内に同じIDを持つ2つのスレッドが同時に発生することを防ぎます。

+0

エントリはいつマップから削除されますか?潜在的に非常に大量のデータになる可能性があります。 –

+0

明示的に消去するものを除いて、絶対にしないでください。 –

+0

ええ、私の質問は本当にです:私たちはマップを整理するために何を思いつくことができますか?エントリを削除するのは難しいですが、余分な同期ブロックが必要になると思います –

0

モニター/ロックをConcurrentHashMapに格納し、idによって適切なロックを取得できます。不要なIDのマップをマップから削除できるようにするには、WeakReferencesを使用できます。それは扱うのが少し難しいですが、実行可能です。

弱参照は、ロックオブジェクトが少なくとも1つの他のスレッドによって参照されている場合、すべてのスレッドがそのインスタンスを使用するようにします。何も使用しない場合、WeakReference.get()はnullを返します。そのような

何か:

private static final ConcurrentMap<Integer, WeakReference<Object>> MONITORS = new ConcurrentHashMap<>(); 

public void method(int id) { 
    Object lock = getLock(id); 
    synchronized (lock) { 

    } 
} 

private Object getLock(int id) { 
    Object newLock = new Object(); 
    WeakReference<Object> newReference = new WeakReference<>(newLock); 
    WeakReference<Object> oldReference = MONITORS.computeIfAbsent(id, _ -> new WeakReference<>(newLock)); 
    Object oldLock = oldReference.get(); 
    while (oldLock == null) { 
     if (MONITORS.replace(id, oldReference, newReference)) { 
      return newLock; 
     } else { 
      oldReference = MONITORS.get(id); 
     } 
    } 
    return oldLock; 

} 

private void maintain() { 
    for (Iterator<WeakReference<Object>> iterator = MONITORS.values().iterator(); iterator.hasNext();) { 
     WeakReference<Object> reference = iterator.next(); 
     if (reference.get() == null) { 
      iterator.remove(); 
     } 
    } 
} 
0

この質問を読みました。セマフォの実装が心に浮かび上がる。基本的には、Javaコード内のリソースまたはロジックセットへの一定量のアクセス許可を作成することができます。クリティカルコードにアクセスするためのクリティカルなリソースを持つオブジェクトの内部では、アクセススレッドが許可を得るか、拒否されるようなロジックを実装できます。これに関する素晴らしいことは、クリティカルリソースを利用しているスレッドが、終了後に許可をプールに返すことができることです。ここ

は、その上の情報のためのJavaドキュメントのリンクです: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html

関連する問題