我有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)


multiplyThread中的第49行是“ notify() “。。我认为我需要以不同的方式使用同步,但是我不确定如何使用。

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

#1 楼

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

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

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


评论


while(!JobCompleted);选项通常是个坏主意,因为它会以100%占用CPU的速度不断检查同一变量(请参阅此处)

–马特·里昂
2013年6月1日21:39

while(!JobCompleted)Thread.sleep(5);没有那个问题

–贝尼贝拉
2013年12月25日18:32

它仍然存在完全不同的问题。通常不建议轮询(反复检查是否满足某些条件,即您在做什么),而不是在条件发生变化(例如,我在回答中概述)时通知通知。

–炸弹
2013年12月27日上午7:10

@huseyintugrulbuyukisik,只要当前线程在调用wait的对象上具有锁定,就可以调用wait。使用同步块还是同步方法完全取决于您。

–炸弹
2014年12月4日上午11:59

@BeniBela但是可以肯定肯定会变慢(关于侯赛因的原始问题)。

–托马斯
16年5月22日在10:49

#2 楼

在Java中使用waitnotifynotifyAll方法时,必须记住以下几点:如果希望多个线程在等待锁,请使用notifyAll而不是notify

必须在同步上下文中调用waitnotify方法。有关更多详细说明,请参见链接。
总是在循环中调用wait()方法,因为如果多个线程正在等待锁,并且其中一个得到了锁并重置了条件,那么其他线程在唤醒后需要检查条件以查看它们是否需要再次等待,或者可以开始处理。
使用相同的对象来调用wait()notify()方法;每个对象都有自己的锁,因此在对象A上调用wait()和在对象B上调用notify()毫无意义。


#3 楼

您是否需要全部穿线?我想知道您的矩阵有多大,以及打印一个线程而另一个执行乘法是否有好处。

也许这段时间值得在进行相对复杂的线程工作之前进行测量?单元的乘法(也许“ n”是您可用的核心数),然后使用ExecutorService和Future机制同时调度多个乘法。

这样,您可以根据内核数量优化工作,并且使用的是更高级别的Java线程工具(可以简化工作)。将结果写回到接收矩阵中,然后在完成所有“未来”任务后简单地打印此结果。

评论


+1 @Greg我认为您应该看看Brian指出的java.util.concurrent包。

– ATorras
09年5月20日在8:42

+1并阅读本书,这也将教给您正确的使用wait()和notify()jcip.net的方法

– Chii
09年5月20日在12:44

#4 楼

假设您有一个名为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();       
   }

}


#5 楼

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

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


#6 楼

notify()也需要同步

#7 楼

我将通过一个简单的示例向您展示在Java中使用waitnotify的正确方法。
因此,我将创建两个名为ThreadA和ThreadB的类。 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
            }
        }
    }


#8 楼

如果需要,可以简单使用如何交替执行线程:-

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


评论


当我有4个操作要以同步方式执行时,该如何工作?

– saksham agarwal
19年2月14日在9:58

#9 楼

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

br />

#10 楼

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

#11 楼

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

#12 楼

使用wait()调用synchronized(this)方法时,您已正确保护了代码块。

但是在不使用保护块的情况下调用notify()方法时,您并没有采取相同的预防措施:synchronized(this)synchronized(someObject)

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


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


最近7年中发生了许多变化,下面的SE问题让我们研究synchronized的其他替代方法:

如果可以使用同步的,为什么要使用ReentrantLock(this)

同步与锁定

在Java中避免同步(this)?