如何在Java中使用wait和notify而不出现IllegalMonitorStateException?

发布于 2024-07-21 06:19:55 字数 3462 浏览 10 评论 0原文

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

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

I have 2 matrices and I need to multiply them and then print the results of each cell. As soon as one cell is ready I need to print it, but for example I need to print the [0][0] cell before cell [2][0] even if the result of [2][0] is ready first. So I need to print it by order.
So my idea is to make the printer thread wait until the multiplyThread notifies it that the correct cell is ready to be printed and then the printerThread will print the cell and go back to waiting and so on..

So I have this thread that does the multiplication:

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();
}

Thread that prints the result of each cell:

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] + " ");
            }
        }
    }

Now it throws me these exceptions:

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)

line 49 in multiplyThread is the "notify()"..I think I need to use the synchronized differently but I am not sure how.

If anyone can help this code to work I will really appreciate it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

我乃一代侩神 2024-07-28 06:19:55

能够调用 notify( ) 你需要在同一个对象上同步。

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

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

To be able to call notify() you need to synchronize on the same object.

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

/* different thread / object */
synchronized (someObject) {
    someObject.notify();
}
静待花开 2024-07-28 06:19:55

在 Java 中使用 waitnotifynotifyAll 方法时,必须记住以下事项:

  1. 使用 notifyAll 而不是如果您预计有多个线程正在等待锁定,请通知
  2. wait 和 < code>notify 方法必须在同步上下文中调用。 请参阅链接以获取更详细的说明。
  3. 始终在循环中调用 wait() 方法,因为如果多个线程正在等待锁,其中一个线程获得锁并重置条件,则其他线程需要在唤醒后检查条件看看他们是否需要再次等待或可以开始处理。
  4. 使用同一个对象来调用 wait()notify() 方法; 每个对象都有自己的锁,因此在对象 A 上调用 wait() 并在对象 B 上调用 notify() 没有任何意义。

While using the wait and notify or notifyAll methods in Java the following things must be remembered:

  1. Use notifyAll instead of notify if you expect that more than one thread will be waiting for a lock.
  2. The wait and notify methods must be called in a synchronized context. See the link for a more detailed explanation.
  3. Always call the wait() method in a loop because if multiple threads are waiting for a lock and one of them got the lock and reset the condition, then the other threads need to check the condition after they wake up to see whether they need to wait again or can start processing.
  4. Use the same object for calling wait() and notify() method; every object has its own lock so calling wait() on object A and notify() on object B will not make any sense.
不甘平庸 2024-07-28 06:19:55

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

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

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

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

Do you need to thread this at all ? I'm wondering how big your matrices are, and whether there's any benefit in having one thread print whilst the other does the multiplication.

Perhaps it would be worth measuring this time before doing the relatively complex threading work ?

If you do need to thread it, I would create 'n' threads to perform the multiplication of the cells (perhaps 'n' is the number of cores available to you), and then use the ExecutorService and Future mechanism to dispatch multiple multiplications simultaneously.

That way you can optimise the work based on the number of cores, and you're using the higher level Java threading tools (which should make life easier). Write the results back into a receiving matrix, and then simply print this once all your Future tasks have completed.

那伤。 2024-07-28 06:19:55

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

}

Let's say you have 'black box' application with some class named BlackBoxClass that has method doSomething();.

Further, you have observer or listener named onResponse(String resp) that will be called by BlackBoxClass after unknown time.

The flow is simple:

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

Lets say we don't know what is going on with BlackBoxClass and when we should get answer but you don't want to continue your code till you get answer or in other word get onResponse call. Here enters 'Synchronize helper':

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) {
        }
    }
}
}

Now we can implement what we want:

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();       
   }

}
梦里寻她 2024-07-28 06:19:55

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

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

You can only call notify on objects where you own their monitor. So you need something like

synchronized(threadObject)
{
   threadObject.notify();
}
芯好空 2024-07-28 06:19:55

notify() 也需要同步

notify() needs to be synchronized as well

伴随着你 2024-07-28 06:19:55

我将通过简单的示例向您展示在 Java 中使用 waitnotify 的正确方法。
因此,我将创建两个名为 ThreadA 和 ThreadA 的类。 线程B。 线程A将调用线程B。

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
            }
        }
    }

I'll right simple example show you the right way to use wait and notify in Java.
So I'll create two class named ThreadA & ThreadB. ThreadA will call 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);
        }
    }
} 

and for Class 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
            }
        }
    }
感情旳空白 2024-07-28 06:19:55

如果您想选择如何执行线程,则可以简单使用:-

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

Simple use if you want How to execute threads alternatively :-

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();
    }
}

response :-

T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
T1:A
T2:B
温柔嚣张 2024-07-28 06:19:55

我们可以调用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!");
}

通过调用同一类的另一个对象上的notify来恢复this一样

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

we can call notify to resume the execution of waiting objects as

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!");
}

resume this by invoking notify on another object of same class

public synchronized notifyJoy() {
    joy = true;
    notifyAll();
}
物价感观 2024-07-28 06:19:55

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

For this particular problem, why not store up your various results in variables and then when the last of your thread is processed you can print in whatever format you want. This is especially useful if you are gonna be using your work history in other projects.

心在旅行 2024-07-28 06:19:55

这看起来像是生产者-消费者模式的情况。 如果您使用的是 java 5 或更高版本,您可以考虑使用阻塞队列(java.util.concurrent.BlockingQueue)并将线程协调工作留给底层框架/api 实现。
请参阅示例
爪哇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

This looks like a situation for producer-consumer pattern. If you’re using java 5 or up, you may consider using blocking queue(java.util.concurrent.BlockingQueue) and leave the thread coordination work to the underlying framework/api implementation.
See the example from
java 5:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html
or java 7 (same example):
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

单调的奢华 2024-07-28 06:19:55

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

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

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

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

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

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

同步与锁定

避免在 Java 中使用同步(this)?

You have properly guarded your code block when you call wait() method by using synchronized(this).

But you have not taken same precaution when you call notify() method without using guarded block : synchronized(this) or synchronized(someObject)

If you refer to oracle documentation page on Object class, which contains wait() ,notify(), notifyAll() methods, you can see below precaution in all these three methods

This method should only be called by a thread that is the owner of this object's monitor

Many things have been changed in last 7 years and let's have look into other alternatives to synchronized in below SE questions:

Why use a ReentrantLock if one can use synchronized(this)?

Synchronization vs Lock

Avoid synchronized(this) in Java?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文