132

我有 2 个矩阵,我需要将它们相乘,然后打印每个单元格的结果。一旦一个单元格准备好,我就需要打印它,但是例如,即使 [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()”..我想我需要以不同的方式使用同步,但我不确定如何。

如果有人可以帮助此代码工作,我将非常感激。

4

12 回答 12

219

为了能够调用notify(),您需要在同一个对象上进行同步。

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

/* different thread / object */
synchronized (someObject) {
    someObject.notify();
}
于 2009-05-20T08:21:52.957 回答
64

在 Java 中使用waitand notifyornotifyAll方法时,必须记住以下几点:

  1. 如果您预计多个线程将等待锁定, 请使用notifyAll而不是。notify
  2. 和方法必须在同步上下文中wait调用notify。有关更详细的说明,请参阅链接。
  3. 总是wait()在循环中调用该方法,因为如果多个线程正在等待一个锁,其中一个获得锁并重置条件,那么其他线程需要在唤醒后检查条件,看看是否需要再次等待或可以开始处理。
  4. wait()调用和notify()方法使用同一个对象;每个对象都有自己的锁,因此调用wait()对象 A 和notify()对象 B 没有任何意义。
于 2011-06-03T00:12:54.443 回答
21

你需要穿这个吗?我想知道你的矩阵有多大,以及让一个线程打印而另一个线程进行乘法是否有任何好处。

在进行相对复杂的线程工作之前,也许这次值得测量一下?

如果您确实需要线程化,我会创建“n”个线程来执行单元的乘法(也许“n”是您可用的内核数),然后使用ExecutorServiceFuture机制同时调度多个乘法.

这样,您可以根据内核数量优化工作,并且您正在使用更高级别的 Java 线程工具(这应该让生活更轻松)。将结果写回接收矩阵,然后在所有未来任务完成后简单地打印出来。

于 2009-05-20T08:34:37.517 回答
14

假设您有一个“黑匣子”应用程序,其中包含一些名为BlackBoxClassmethod的类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();       
   }

}
于 2012-10-15T22:25:20.020 回答
7

您只能在您拥有其监视器的对象上调用通知。所以你需要类似的东西

synchronized(threadObject)
{
   threadObject.notify();
}
于 2009-05-20T08:23:12.953 回答
6

notify()也需要同步

于 2009-05-20T08:16:55.387 回答
3

我会用正确的简单示例向您展示在 Java中正确使用wait和使用的方法。notify所以我将创建两个名为ThreadAThreadB的类。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
            }
        }
    }
于 2015-06-19T09:47:11.850 回答
3

如果你想简单使用如何交替执行线程: -

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
于 2017-05-10T05:36:50.017 回答
2

我们可以调用 notify 来恢复等待对象的执行

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();
}
于 2016-05-18T10:46:36.053 回答
0

对于这个特殊问题,为什么不将各种结果存储在变量中,然后在处理完线程的最后一个时,您可以以所需的任何格式打印。如果您要在其他项目中使用您的工作历史,这将特别有用。

于 2014-06-01T01:52:17.600 回答
0

这看起来像是生产者-消费者模式的情况。如果您使用的是 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

于 2014-11-06T17:33:20.863 回答
0

当您wait()使用synchronized(this).

notify()但是当您调用方法而不使用保护块时,您没有采取同样的预防措施:synchronized(this)synchronized(someObject)

如果您参考Object类的 oracle 文档页面,其中包含wait(), notify(),notifyAll()方法,您可以在所有这三个方法中看到以下注意事项

此方法只能由该对象的监视器所有者的线程调用

在过去的 7 年中,许多事情都发生了变化,让我们看看synchronized以下 SE 问题的其他替代方案:

如果可以使用 synchronized(this),为什么还要使用 ReentrantLock?

同步与锁定

在 Java 中避免同步(this)?

于 2016-05-22T09:55:58.267 回答