0

ArrayList2つの別々のスレッドを使用して変更するために、待機/通知メカニズムを実装しようとしました。

最初の反復では問題なく動作するように見えますが、2 回目の反復ではaddToArray()メソッドで永遠に待機します。メソッドで永遠に待機している理由がわかりませんか? 私の理解によると、他のスレッド(アイテムの削除)は、他のスレッドが待機するときにピックアップする必要があります。

見て、バグの可能性がある場合は指摘してください。Vectorスレッドセーフな操作に使用できることはわかっていますが、それは私が望んでいるものではありません。

package threadTest;
import java.util.*;

public class DhagaJava {

    public static void main(String...strings){
        ArrayModification am = new ArrayModification();

        Thread t1 = new Thread(new AddToArray(am));
        Thread t2 = new Thread(new RemoveFromArray(am));
        t1.start();
        t2.start();
    }
}

class ArrayModification{
    boolean added = false;
    ArrayList<Integer> al;

    ArrayModification(){
        al = new ArrayList<Integer>();
    }

    public synchronized void addToArrayList(int x) {
        if (added == true){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.al.add(x);
        System.out.println(al);
        System.out.println("Added!! :)");
        added = true;
        notifyAll();
    }

    public synchronized void removeFromList(){
        if( added== false){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(al);     
        this.al.remove(0);
        System.out.println("Removed!! :' ");
        added = false;
        notifyAll();
    }
}

class AddToArray implements Runnable{

    ArrayModification ma;

    AddToArray(ArrayModification m){
        this.ma = m;
    }

    public void run() { 
        for (int i = 0; i<10; i++)
            ma.addToArrayList(i);
    }
}

class RemoveFromArray implements Runnable{

    ArrayModification ma;

    RemoveFromArray(ArrayModification a){
        this.ma = a;
    }

    public void run(){
            ma.removeFromList();
    }
}

class RemoveFromArray implements Runnable{

      ArrayModification ma;

      RemoveFromArray(ArrayModification a){
            this.ma = a;
      }

      public void run(){
            //for(int j=11;j<20; j++)
                  ma.removeFromList();
      }
}

出力は次のとおりです。

[0]
Added!! :)
[0]
Removed!! :' 
[1]
Added!! :)
4

3 に答える 3

1

唯一の問題は、removeFromList が 1 回しか実行されないことです (for ループを推奨したため)。これが、ログに 2 番目の削除がなく、addToArrayList が永遠に待機し始める理由です (誰かがリストからアイテムを削除するのを待ちます)。

コメントを削除した後、コードを試してみましたが、正常に動作します!

于 2013-02-17T11:13:23.490 に答える
1

車輪を再発明するのではなく、CopyOnWriteArrayList. すぐに使用できる並行性が付属しています。

于 2012-06-01T07:27:49.070 に答える
0

あなたの notifyAll は、同期ブロック内にあります。そのため、彼が行動する前に他のスレッドが目覚める可能性があります。そのため、ブロックされている可能性があります。

私はあなたの目標を理解したかどうかわかりませんが、この構造はより良いかもしれません:

public void addToArrayList(int x) {
    synchonized(this.al) {
        if (added == true){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.al.add(x);
        System.out.println(al);
        System.out.println("Added!! :)");
        added = true;
    }
    notifyAll();
}

しかし、これは非常に複雑です。もっと一般的な目標はありますか?スレッドが 1 つしかないタスク キューの方が適しているかもしれません。その方が高速で、軽量で、シンプルで、並列化されています (まったくそうではありません)。

于 2012-06-01T07:19:43.150 に答える