1

私の Java コードでは、threadB がnb *threadAを作成し、 myobjの値がnbと等しくなるまで待機します。 myobjは最初は 0 に等しく、各 threadA はそれをインクリメントします。それがnbに等しくなると、最後の threadA が ThreadB に通知します。

プログラムを実行すると、threadB は通知されず、実行を継続しません。このコードのどこに問題があるのか​​、誰か教えてもらえますか?

public class Myclass {
    static Long myobj = new Long(0);
    static int nb = 1;

    public static void main(String[] args) {

        ThreadA[] threadA = new ThreadA[nb];
        ThreadB threadB = new ThreadB(threadA);
    }
}

public class ThreadA extends Thread {
    public ThreadA() {
        this.start();
    }

    public void run() {
        // do lot of computation
        Myclass.myobj = Myclass.myobj + 1;
        if (Myclass.myobj.intValue() == Myclass.myobj.nb) {
            synchronized (Myclass.myobj) {
                Myclass.myobj.notify();
            }
        }
    }
}

public class ThreadB extends Thread {
    ThreadA[] threadA;

    public ThreadB(ThreadA[] threadA) {
        this.threadA = threadA;
        this.start();
    }

    public void run() {
        for (int i = 0; i < threadA.length; i++) {
            threadA[i] = new ThreadA();
        }

        synchronized (Myclass.myobj) {
            while (Myclass.myobj.intValue() != Myclass.myobj.nb) {
                Myclass.myobj.wait();
            }
        }
    }
}
4

2 に答える 2

9

間違っている可能性があるが問題を引き起こさなかったすべてのことに混乱しました。

本当の問題は、

if (Myclass.myobj.intValue() == Myclass.myobj.nb)

これが呼び出されるたびにmyobj<nb


このコードをどのように記述しますか?

int nb = ....

ExecutorService es = Executors.newFixedThreadPool(nb)
for (int i = 0; i < nb; i++)
    es.submit(new Runnable() {
        @Override
        public void run() {
            // do lot of computation
        }
    });
es.shutdown();
es.awaitTermination(1, TimeUnit.HOURS);

ここには改善すべき点がたくさんあるので、それらをリストする必要があると感じています

  • 適切なフォーマットを使用してください。
  • コンパイルできるコードを提供する
  • 可変フィールドをロックしないでください。毎回異なるオブジェクトをロックすることになるため、これは期待どおりには機能しません。
  • Longを使用する場合は a を使用しないでくださいlong。この原因で、あなたはint.
  • new Long(0)より効率的なオートボクシングを使用できるため、を作成しないでください。これを行う場合は、ロックオンするオブジェクトとして使用しないでください。
  • staticスレッド間で可変フィールドを使用しないでください。
  • 延長しないでくださいThread。スレッドに渡される Runnable を作成します。
  • コンストラクターでスレッドを開始しないでください。
  • スレッドを別のスレッドに渡すために配列を使用しないでください。特に、そのスレッドが開始されるまで設定されないためです。
  • 同期ブロック内の保護された値のみを読み取り/チェックします。
  • あるスレッドを使用して、元のスレッドに戻される別のスレッドを作成することはありません。

ただし、基本的な問題は、通知しているオブジェクトとは異なるオブジェクトを待機していることです。

synchronized(Myclass.myobj){ // lock the object you might be waiting on.
    Myclass.myobj=Myclass.myobj+1; // change this to another object.
    Myclass.myobj.notify(); // notify a different object.
}
于 2012-09-26T10:35:21.163 に答える
2

ThreadA は Myclass.myobj に新しいオブジェクトを割り当て、この新しいオブジェクトに通知するため、あるオブジェクトを待機し、別のオブジェクトに通知しています。

専用のロック オブジェクトを使用し、myObj へのすべてのアクセスがこのロック オブジェクトによって保護されていることを確認してください。

または、java.util.concurrent パッケージから高レベルの同時実行抽象化を使用することをお勧めします。

于 2012-09-26T10:34:01.387 に答える