0

リンクリストの最大値を見つけるために4つのスレッドがあります。なぜこの変数を同期させる必要がありますか

これは私のスレッドクラスです:

public class MyThread extends Thread { 

    LinkedList<Integer> list; 
    int max = Integer.MIN_VALUE; 

    public MyThread(LinkedList<Integer> list) { 
     this.list = list; 
    } 

    public void run() { 
     synchronized (list) {  /* If I don't synchronize list, I get a NoSuchElementException at list.remove() */ 
      while (!list.isEmpty()) { 
       int num = list.remove(); 

       if (num > max) { 
        max = num; 
       } 
      } 
     } 
    } 
} 

そしてここでは、mainメソッドを持つクラスである:上記のコードで

public class Application { 

    public static void main(String args[]) throws InterruptedException { 
     LinkedList<Integer> list = new LinkedList<Integer>(); 

     for (int i = 0; i < 10; i++) { 
      list.add(i); 
     } 

     MyThread t1 = new MyThread(list); 
     MyThread t2 = new MyThread(list); 
     MyThread t3 = new MyThread(list); 
     MyThread t4 = new MyThread(list); 

     t1.start(); 
     t2.start(); 
     t3.start(); 
     t4.start(); 

     t1.join(); 
     t2.join(); 
     t3.join(); 
     t4.join(); 

     System.out.println(t1.max); 
     System.out.println(t2.max); 
     System.out.println(t3.max); 
     System.out.println(t4.max); 
    } 
} 

、私はrunメソッド内list変数を同期化する必要がありますそうでなければNoSuchElementExceptionlist.remove()にします。これはなぜですか?

各スレッドには独自のリストがありませんので、スレッドの干渉はありませんか?

ありがとうございます。

+0

各 'MyThread'コンストラクタは同じリスト参照で呼び出されるので、すべてのスレッドは同じリストを使用します。 – korolar

+2

'List'をすべての' Thread'に渡すと、なぜあなたはそれぞれに独自のコピーがあると思いますか? –

+0

[Javadocを読む](https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html)、特に太字で「**この実装は同期**。 –

答えて

1

私は@Rishiが対処することをあなたの質問の別の部分に対処します:

を一切ねじ干渉がないように、各スレッドはそれ自身のリストを持っていませんか?

簡単な答えは:いいえ、それはありません。 Javaでは、クラス・タイプのオブジェクトをコンストラクタまたはメソッドに渡すと、obejct自体を渡すのではなく、obejctへのポインタが渡されます。リンクされたリストの個別のコピーを各スレッドに渡す場合は、LinkedList#Cloneを使用する必要があります。

クローンを使用すると、スレッドがそのリンクリストから1つの整数を削除すると、それは他のリンクリストから削除されません。これを適切に並列化するには、すべての番号を持つ標準配列を使用し、この配列のセグメントを各スレッドに割り当てる必要があります(つまり、スレッド1は0-9、スレッド2は10-19、スレッド3は20-29、等。)。配列の内容は、内容が配列に格納された後に作成されたスレッドに表示されます。


スレッドを拡張しないでください。代わりに、Runnableを拡張してスレッドに渡します。さらに、後でスレッドの数を簡単に変更できるので、配列(リスト)は4つの別々の変数より優れています。

1

LinkedListはスレッドセーフではありません。したがって、複数のスレッドでLinkedListを操作する場合は、外部同期が必要です。

この場合、poll()メソッドが便利なBlockingQueueを使用できます。

+0

それはスレッドセーフではないことだけではありません: 'isEmpty()'と 'hasNext()'は原子的には実行されません。すなわち、別のスレッドが 'isEmpty()'がfalseを返す原因となった要素を挟んで盗むことができます。 'BlockingQueue'に+1してください。 –

関連する問題