質問

2 つの行列があり、それらを乗算して各セルの結果を出力する必要があります。1 つのセルの準備ができたらすぐにそれを印刷する必要がありますが、たとえば、[2][0] の結果が最初に準備できたとしても、セル [2][0] の前に [0][0] セルを印刷する必要があります。 。したがって、注文して印刷する必要があります。したがって、私のアイデアは、プリンタースレッドを待機させることです。 multiplyThread 正しいセルを印刷する準備ができたことを通知してから、 printerThread セルを出力し、待機状態に戻ります。

したがって、乗算を行うこのスレッドがあります。

public void run() 
{
    int countNumOfActions = 0; // How many multiplications have we done
    int maxActions = randomize(); // Maximum number of actions allowed

    for (int i = 0; i < size; i++)
    {       
        result[rowNum][colNum] = result[rowNum][colNum] + row[i] * col[i];
        countNumOfActions++;
        // Reached the number of allowed actions
        if (countNumOfActions >= maxActions)
        {
            countNumOfActions = 0;
            maxActions = randomize();
            yield();
        }   
    }
    isFinished[rowNum][colNum] = true;
    notify();
}

各セルの結果を出力するスレッド:

public void run()
{
    int j = 0; // Columns counter
    int i = 0; // Rows counter
    System.out.println("The result matrix of the multiplication is:");

    while (i < creator.getmThreads().length)
    {
        synchronized (this)
        {
            try 
            {
                this.wait();
            } 
            catch (InterruptedException e1) 
            {
            }
        }
        if (creator.getmThreads()[i][j].getIsFinished()[i][j] == true)
        {
            if (j < creator.getmThreads()[i].length)
            {
                System.out.print(creator.getResult()[i][j] + " ");
                j++;
            }
            else
            {
                System.out.println();
                j = 0;
                i++;
                System.out.print(creator.getResult()[i][j] + " ");
            }
        }
    }

現在、次の例外がスローされます。

Exception in thread "Thread-9" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-6" Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-5" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-8" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-7" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-11" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-10" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-12" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at multiplyThread.run(multiplyThread.java:49)

49行目 multiplyThread は「notify()」です。同期を別の方法で使用する必要があると思いますが、方法がわかりません。

誰かがこのコードが機能するよう手伝ってくれたら、本当に感謝します。

役に立ちましたか?

解決

電話できるようになるには 通知() 同じオブジェクト上で同期する必要があります。

synchronized (someObject) {
    someObject.wait();
}

/* different thread / object */
synchronized (someObject) {
    someObject.notify();
}

他のヒント

使用中に、 wait そして notify または notifyAll Java のメソッドでは、次のことに留意する必要があります。

  1. 使用 notifyAll の代わりに notify 複数のスレッドがロックを待機していることが予想される場合。
  2. wait そして notify メソッドは同期されたコンテキストで呼び出す必要があります. 。より詳細な説明については、リンクを参照してください。
  3. 常に電話してください wait() 複数のスレッドがロックを待機していて、そのうちの 1 つがロックを取得して条件をリセットした場合、他のスレッドはウェイクアップ後に条件をチェックして、再度待機する必要があるか、処理を開始できるかを確認する必要があるためです。 。
  4. 呼び出しに同じオブジェクトを使用する wait() そして notify() 方法;すべてのオブジェクトには独自のロックがあるため、 wait() オブジェクト A と notify() オブジェクト B については意味がありません。

そもそもこれをスレッド化する必要がありますか?行列がどれくらいの大きさなのか、そして一方のスレッドが乗算を実行している間にもう一方のスレッドが出力することに何か利点があるのか​​どうか疑問に思っています。

おそらく、比較的複雑なねじ切り作業を行う前に、この時間を測定する価値があるでしょうか?

スレッド化する必要がある場合は、セルの乗算を実行するために「n」個のスレッドを作成し (おそらく「n」は利用可能なコアの数です)、 ExecutorService そして 未来 複数の乗算を同時にディスパッチするメカニズム。

こうすることで、コアの数に基づいて作業を最適化することができ、より高レベルの Java スレッド ツールを使用することになります (作業が容易になるはずです)。結果を受信マトリックスに書き込み、すべての将来のタスクが完了したらこれを印刷するだけです。

あなたがメソッドのBlackBoxClassを持っているいくつかのクラスの名前doSomething();で「ブラックボックス」アプリケーションを持っているとしましょう。

さらに、あなたがオブザーバーまたは未知の時間後にonResponse(String resp)によって呼び出されるリスナーという名前のBlackBoxClassを持っています。

の流れは単純です:

private String mResponse = null; 
 ...
BlackBoxClass bbc = new BlackBoxClass();
   bbc.doSomething();
...
@override
public void onResponse(String resp){        
      mResponse = resp;       
}

私たちはBlackBoxClassとするとき、我々は答えを得る必要がありますが、あなたは答えを得るかonResponseコールを取得し、他の言葉にまであなたのコードを継続したくないと何が起こっているか分からないと言うことができます。ここでは '同期ヘルパー' を入力します:

public class SyncronizeObj {
public void doWait(long l){
    synchronized(this){
        try {
            this.wait(l);
        } catch(InterruptedException e) {
        }
    }
}

public void doNotify() {
    synchronized(this) {
        this.notify();
    }
}

public void doWait() {
    synchronized(this){
        try {
            this.wait();
        } catch(InterruptedException e) {
        }
    }
}
}

今、私たちは、私たちが望むものを実装することができます:

public class Demo {

private String mResponse = null; 
 ...
SyncronizeObj sync = new SyncronizeObj();

public void impl(){

BlackBoxClass bbc = new BlackBoxClass();
   bbc.doSomething();

   if(mResponse == null){
      sync.doWait();
    }

/** at this momoent you sure that you got response from  BlackBoxClass because
  onResponse method released your 'wait'. In other cases if you don't want wait too      
  long (for example wait data from socket) you can use doWait(time) 
*/ 
...

}


@override
public void onResponse(String resp){        
      mResponse = resp;
      sync.doNotify();       
   }

}

あなただけが自分のモニターを所有するオブジェクトに通知呼び出すことができます。だからあなたのような何かを必要とする

synchronized(threadObject)
{
   threadObject.notify();
}

notify()も同様に同期させる必要がある。

簡単な例で正しい使い方を説明します wait そして notify ジャワでは。そこで、次の名前の 2 つのクラスを作成します。 スレッドA & スレッドB. 。ThreadA は ThreadB を呼び出します。

public class ThreadA {
    public static void main(String[] args){
        ThreadB b = new ThreadB();//<----Create Instance for seconde class
        b.start();//<--------------------Launch thread

        synchronized(b){
            try{
                System.out.println("Waiting for b to complete...");
                b.wait();//<-------------WAIT until the finish thread for class B finish
            }catch(InterruptedException e){
                e.printStackTrace();
            }

            System.out.println("Total is: " + b.total);
        }
    }
} 

クラス ThreadB の場合:

class ThreadB extends Thread{
    int total;
    @Override
    public void run(){
        synchronized(this){
            for(int i=0; i<100 ; i++){
                total += i;
            }
            notify();//<----------------Notify the class wich wait until my    finish 
//and tell that I'm finish
            }
        }
    }

私たちは、

のように待機しているオブジェクトの実行を再開する通知呼び出すことができます
public synchronized void guardedJoy() {
    // This guard only loops once for each special event, which may not
    // be the event we're waiting for.
    while(!joy) {
        try {
            wait();
        } catch (InterruptedException e) {}
    }
    System.out.println("Joy and efficiency have been achieved!");
}

同じクラスの別のオブジェクトに通知を呼び出すことによって、これを再開

public synchronized notifyJoy() {
    joy = true;
    notifyAll();
}

シンプルな使用あなたが代わりにスレッドを実行するためにどのようにしたい場合: -

public class MyThread {
    public static void main(String[] args) {
        final Object lock = new Object();
        new Thread(() -> {
            try {
                synchronized (lock) {
                    for (int i = 0; i <= 5; i++) {
                        System.out.println(Thread.currentThread().getName() + ":" + "A");
                        lock.notify();
                        lock.wait();
                    }
                }
            } catch (Exception e) {}
        }, "T1").start();

        new Thread(() -> {
            try {
                synchronized (lock) {
                    for (int i = 0; i <= 5; i++) {
                        System.out.println(Thread.currentThread().getName() + ":" + "B");
                        lock.notify();
                        lock.wait();
                    }
                }
            } catch (Exception e) {}
        }, "T2").start();
    }
}
  

応答: -

T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B

この特定の問題のために、なぜ変数であなたの様々な結果を保存しないと、あなたのスレッドの最後が処理されるとき、あなたはあなたが好きな形式で印刷することができます。あなたがつもり他のプロジェクトで、あなたの作業履歴を使用している場合に特に便利です。

これは、生産者 - 消費者パターンの状況のように見えます。あなたは、最大のJava 5またはを使用している場合は、(java.util.concurrent.BlockingQueue)をブロックキューを使用することを検討し、基礎となるフレームワーク/ API実装にスレッド協調作業を残すことができます。 からの例を参照してください。 javaの5: http://docs.oracle.com /javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.htmlする またはJava 7(同じ例)。 http://docs.oracle.com/javase /7/docs/api/java/util/concurrent/BlockingQueue.htmlする

あなたがwait()を使用してsynchronized(this)メソッドを呼び出したときに

あなたはあなたのコードブロックを適切に守られてきました。

しかし、あなたが保護されたブロックを使用せずにnotify()メソッドを呼び出すときに同じ予防措置を取っていない:synchronized(this)またはsynchronized(someObject)

あなたはオブジェクト上で、Oracleのマニュアルページを参照している場合wait()notify()notifyAll()のメソッドが含まれてのクラスは、あなたがすべてのこれらの三つの方法で予防措置の下に見ることができます。

  

このメソッドは、このオブジェクトのモニターを所有するスレッドによって呼び出されなければなりません。

多くの事は過去7年間に変更され、のは、SEの質問の下でsynchronizedするために、他の選択肢に見てみましょうされています:

1ができれば、

なぜReentrantLockのを使用使用する同期(この)?

同期ロックの対

避けJavaで(この)同期には

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top