3

1つをintの共有配列に書き込むには、2つのスレッドが必要です。両方のスレッドは、その配列のすべての要素に書き込む必要があります。各スレッドは1または7のいずれかを書き込み、結果は171717171(または71717171)のようになります。これを行うには、最初のThread1を位置0に書き込んでから、待機します。Thread2は位置0と1に書き込み、Thread1に通知して待機します。Thread1は位置1と2に書き込み、Thread2に通知して待機します。次のコードを使用すると、正しい出力が得られますが、JPFで実行するとデッドロックが検出されます。何が悪いのかわからないので、本当にイライラします。何かアドバイスをいただければ幸いです。

import java.util.logging.Level;
import java.util.logging.Logger;


public class WriterThreadManager {

    private int[] array = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    private Thread thread7;
    private Thread thread1;

    public static void main(String[] args) {
        WriterThreadManager mng = new WriterThreadManager();
        mng.exec();

    }

    public WriterThreadManager() {
        thread7 = new Thread(new WriterRunnable(this, 7));
        thread1 = new Thread(new WriterRunnable(this, 1));
    }

    public void overwriteArray(int pos, int num) {
        array[pos] = num;
        printArray();
    }

    private  void printArray() {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]);
        }
        System.out.println("");
    }

    public synchronized void stopThread() {
        try {
            this.wait();
        } catch (InterruptedException ex) {
            Logger.getLogger(WriterThreadManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public synchronized void wakeUpThread() {
        notifyAll();
    }

    private void exec() {
        thread7.start();
        thread1.start();
    }

    public int length() {
        return array.length;
    }
}



public class WriterRunnable implements Runnable {

    private WriterThreadManager mng;
    private int numberToWrite;
    private static boolean flag = true;

    @Override
    public void run() {
        int counter = 0;
        int j = 0;

        //first thread to get in should write only at 
        //position 0 and then wait.
        synchronized (mng) {
            if (flag) {
                flag = false;
                mng.overwriteArray(0, numberToWrite);
                j = 1;
                waitForOtherThread();
            }
        }
        for (int i = j; i < mng.length(); i++) {
            mng.overwriteArray(i, numberToWrite);
            counter++;
            if (i == mng.length() - 1) {
                mng.wakeUpThread();
                break;
            }
            if (counter == 2) {
                waitForOtherThread();
                counter = 0;
            }
        }
    }

    private void waitForOtherThread() {
        mng.wakeUpThread();
        mng.stopThread();
    }

    public WriterRunnable(WriterThreadManager ar, int num) {
        mng = ar;
        numberToWrite = num;
    }
}

ps:実行の例:

1000000000
7000000000
7700000000
7100000000
7110000000
7170000000
7177000000
7171000000
7171100000
7171700000
7171770000
7171710000
7171711000
7171717000
7171717700
7171717100
7171717110
7171717170
7171717177
7171717171

JPFからのエラースナップショットは次のとおりです。

thread java.lang.Thread:{id:1,name:Thread-1,status:WAITING,priority:5,lockCount:1,suspendCount:0}
  waiting on: WriterThreadManager@152
  call stack:
    at java.lang.Object.wait(Object.java)
    at WriterThreadManager.stopThread(WriterThreadManager.java:43)
    at WriterRunnable.waitForOtherThread(WriterRunnable.java:53)
    at WriterRunnable.run(WriterRunnable.java:45)

thread java.lang.Thread:{id:2,name:Thread-2,status:WAITING,priority:5,lockCount:1,suspendCount:0}
  waiting on: WriterThreadManager@152
  call stack:
    at java.lang.Object.wait(Object.java)
    at WriterThreadManager.stopThread(WriterThreadManager.java:43)
    at WriterRunnable.waitForOtherThread(WriterRunnable.java:53)
    at WriterRunnable.run(WriterRunnable.java:45)
4

3 に答える 3

3

私はレースがこの方法によるものだと信じています:

private void waitForOtherThread() {
    mng.wakeUpThread();
    mng.stopThread();
}

個々のメソッドwakeUpThread()stopThread()メソッドが同期している間、これらの呼び出し間で予期しないスレッドスケジューリングが発生する可能性があります。

検討:

thread7 - notify thread1 to wakup
thread1 - wake up
thread1 - work to completion
thread1 - notify thread7 to wakeup
thread1 - wait to be notified to wakeup
thread7 - wait to be notified to wakeup

この場合、thread7がwait()を待つ前に、thread1がnotifyAll()を送信したため、デッドロックが発生しました。

別のコンテキストで実行すると、タイミングが乱れ、これらのタイプの動作が表示される可能性があります。

これを避けるために、私はこれを行うことを提案します:

private void waitForOtherThread() {
    synchronized(mng) {
        mng.wakeUpThread();
        mng.stopThread();
    }
}

または、@KumarVivekMitraが提案したようにセマフォを使用することをお勧めします。セマフォは通知システムとカウンターの両方を組み合わせているため、通知と待機の順序は重要ではありません。

于 2012-11-30T21:47:57.200 に答える
0

-ここでのより良いアプローチはjava.util.Semaphores、一度に特定のスレッド数でオブジェクトリソースへのアクセスを決定するのに役立つと思います。

-これを解決するためにを使用することもできますSingleThreadExecutor。これは、2番目のタスクに進む前にタスクを開始して完了するため、ここで同期する必要はありません。

于 2012-11-25T15:19:48.707 に答える
0

ここではなんらかの調整は必要ないと思います。一方のスレッドに偶数の位置を書き込み、もう一方のスレッドに奇数の位置を書き込ませるだけです。両方をできるだけ速く行かせてください。終わり!

于 2012-11-26T07:15:54.627 に答える