2017-12-18 18 views
0

私はライブソケットを取得するために同時に複数のスレッドによって呼び出される以下のメソッドを持っています。それはパラメータとしてLinkedBlockingQueueをとり、それから私は反復し、使用可能なliveSocketがあるかどうかを確認し、使用可能な場合は削除してソケットを返します。LinkedBlockingQueueからelmentsを削除する際に、以下のコードスレッドが安全ですか?

private Optional<Holder> getSocket(final LinkedBlockingQueue<Holder> endPoints) { 
    Optional<Holder> liveSocket = Optional.absent(); 
    if (!endPoints.isEmpty()) { 
     for (Holder state : endPoints) { 
     // check if socket is live? if yes then remove and return that. 
     if (state.isLive()) { 
      liveSocket = Optional.of(state); 
      endPoints.remove(state); 
      return liveSocket; 
     } 
     } 
    } 
    return Optional.absent(); 
    } 

上記のコードがスレッドセーフであるかどうかを確認したいのですか?ここではHolderは不変クラスです。

+0

キュー操作はスレッドセーフですが、含まれているオブジェクトの状態ではありません。 'liveSocket'が状態をチェックするときとキューからそれを削除するときの間で、別のスレッドによって' liveSocket'が非ライブ化されるとどうなりますか? –

答えて

1

キューの操作操作はスレッドセーフなので、remove()ConcurrentModificationExceptionをスローしません。ただし、キューに格納されているオブジェクトの状態に関するスレッドセーフティの問題があります。

Holderオブジェクトの「ライブ」状態をチェックするときとキューから削除するときの競合状態があります。別のスレッドが同じコードで同時に実行されている可能性があり、両方のスレッドが同じオブジェクトを取得する可能性があります。どちらのスレッドでも最後にremove()に電話がかかった場合はfalseが返されますが、結果を調べることはできません。両方のスレッドは、同じオブジェクトを使用しようとします。

検索/削除操作を同期させる必要があります。

好奇心のために、ここで私はConcurrentModificationExceptionLinkedBlockingQueueで発生していないことを示すために使用されるコードだ:

public static void main(String[] args) throws Exception 
{ 
    String[] data = { "a", "b", "c", "d", "e", "f","g" }; 
    LinkedBlockingQueue<String> lb = new LinkedBlockingQueue<>(Arrays.asList(data)); 

    new Thread(() -> 
    { 
     try 
     { 
      Thread.sleep(2000); 
      lb.add("x"); 
      System.out.println("added"); 
      Thread.sleep(1000); 
      lb.remove("e"); 
      System.out.println("removed"); 
     } 
     catch (InterruptedException e) 
     { 
      e.printStackTrace(); 
     } 
    }).start(); 

    for (String s : lb) 
    { 
     System.out.println(s); 
     Thread.sleep(1000); 
    } 
} 

あなたがLinkedBlockingQueueためLinkedListを置き換える場合は、期待通りConcurrentModificationExceptionを取得します。

出力:

a 
b 
added 
c 
removed 
d 
f 
g 
x 
-1

スレッドセーフではなく、単一スレッド内であっても間違っています。 remove()ConcurrentModificationExceptionが表示されます。明示的なIteratorを使用し、Iteratorを使用して削除を行う必要があります。

複数のスレッドを使って正確にするには、ループの周りに同期やセマフォが必要です。

NB isEmpty()のテストは無意味です。反復はすでにそれをチェックする必要があります。犬を飼っておき、自分で吠えないでください。

+0

実際、削除はうまく動作し、 'LinkedBlockingQueue'を持つCMEはありません(単純な' LinkedList'とは対照的に)。 Javadocで説明されているように 'java.util.concurrent'コレクションはスレッドセーフです。ただし、キューに含まれるオブジェクトの周りにスレッドの安全性の問題があります。 –

関連する問題