2016-10-21 1 views
0
public class MyClass { 
    private List<Integer> resources = new ArrayList<>(); 

    public synchronized Integer getAndRemoveResourceOrWait(Integer requestedResource) throws InterruptedException { 
     while(resources.stream().anyMatch((r) -> { return r >= requestedResource; })) { 
      wait(); 
     } 
     Integer found = resources.stream().findFirst((r) -> { 
      return r >= requestedResource; 
     }).get(); 
     resources.remove(found); 
     return found; 
    } 

    public void addResource(Integer resource) { 
     resources.add(resource); 
     notifyAll(); 
    } 
} 

スレッド「A」は、乱数を使用してコードを追加します。 いくつかのスレッドが積極的にgetAndRemoveResourceOrWaitを呼び出します。コレクションから要素を同時に検索して削除するか、または待機します。

メソッドgetAndRemoveResourceOrWaitを同時に実行させるにはどうすればよいですか?

たとえば、スレッド「X」は、リソースコレクションに存在しない変数128を使用してgetAndRemoveResourceOrWaitを呼び出します。だから、それはそれを待っている。待っている間、スレッド "Y"は変数64でgetAndRemoveResourceOrWaitを呼び出し、リソース・コレクション内に存在します。スレッド「Y」は、スレッド「X」が完了するのを待つべきではありません。

答えて

1

メソッドgetAndRemoveResourceOrWaitを同時に実行させるにはどうすればよいですか?

addResource(resource)を呼び出すスレッドとは別のスレッドで実行するだけで済みます。 は、呼び出しを行っているスレッドが応答を得るまでブロックされているという意味で、ブロック(同期)操作であることに注意してください。しかし、getAndRemoveResourceを呼び出す1つのスレッドは、getAndRemoveResourceを呼び出す別のスレッドをブロックしません。鍵は、wait()の呼び出しでのmutexを解放し、mutexが通知されたときに再獲得することです。ここで何が起きるかは、notifyAllが待機中のすべてのスレッドを一度に1つずつアップさせることです。

ただし、addResourceメソッドにバグがあります。メソッドは​​と宣言する必要があります。現在のスレッドがthisのミューテックスを保持している間にnotifyAll()を呼び出さないと、例外が発生します。 (そして、これは共有resourcesオブジェクトへの更新が両方向で...表示されていることを確実にするためにも必要である。)また

は、この実装はうまくスケールするつもりはない。

  • 各待機しているスレッドをすべての更新時にリソースリスト全体をスキャンします。すなわち、addResourceへのすべての通話に適用されます。
  • 待機中のスレッドがリソースを検出すると、リストを2回以上スキャンして削除します。
  • 共有されたMyClassインスタンスにミューテックスを保持している間に、このすべてが行われます。ブロックすると、addResourceもブロックされます。

UPDATEからResource値が一意であると仮定するとは、よりよい解決策はTreeSetArrayListを置き換える使用することです。これは動作するはずです:。

public class MyClass { 
    private TreetSet<Integer> resources = new TreeSet<>(); 

    public synchronized Integer getAndRemoveResourceOrWait(
      Integer resource) throws InterruptedException { 
     while (true) { 
      Integer found = resources.tailSet(resource, true).pollFirst(); 
      if (found != null) { 
       return found; 
      } 
      wait(); 
     } 
    } 

    public synchronized void addResource(Integer resource) { 
     resources.add(resource); 
     notifyAll(); 
    } 
} 

(私もConcurrentSkipListSetを試してみましたが、私はあなたが同じリソースを削除しようとしていた場合の追加と削除しながら、ミューテックスを使用して回避する方法を見つけ出すことができなかった、それが行うことができます。 ..)

関連する問題