java等待并通知

标签 java multithreading wait notify

我正在使用一个整数变量并与两个线程共享。一个线程应该依次打印偶数,一个线程应该打印奇数。 但notify()抛出IllegalMonitorStateException。

package mywaitnotifytest;
public class App {

    public static void main(String[] args) {
        Integer i=0;
        Even even = new Even(i);
        even.setName("EvenThread");
        Odd odd = new Odd(i);
        odd.setName("OddThread");
        even.start();
        odd.start();
    }
}

class Even extends Thread{

    Integer var;

    Even(Integer var){
        this.var=var;
    }

    @Override
    public void run() {
        while(true){
            synchronized (var) {
                if(var%2==0){
                    try {
                        var.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                var++;
                System.out.println(Thread.currentThread().getName()+"  "+var);
                var.notify();
            }
        }

    }
}

class Odd extends Thread{

    Integer var;

    Odd(Integer var){
        this.var=var;
    }

    @Override
    public void run() {
        while(true){
            synchronized (var) {
                if(var%2!=0){
                    try {
                        var.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                var++;
                System.out.println(Thread.currentThread().getName()+"  "+var);
                var.notify();
            }
        }
    }
}

输出是:

奇数线程 1

Exception in thread "OddThread" java.lang.IllegalMonitorStateException

at java.lang.Object.notify(Native Method)

at mywaitnotifytest.Odd.run(App.java:67)

最佳答案

我认为这与给出另一个答案的通常答案有很大不同。

在本例中,您使用的是同步。当您应用锁时,它是在对象上而不是引用上。

<小时/>
synchronized (var) {

这会锁定对象 var 引用,而不是将 var 作为字段锁定。

<小时/>
var++;

这会替换 var 指向的对象。与此相同

var = Integer.valueOf(var.intValue() + 1);

注意:Integer 实际上所有原始包装器都是不可变的。当您对它们执行任何操作时,您实际上是在拆箱、使用原始值进行计算并重新装箱对象。如果被池化,则可以取回相同的对象。例如

Integer i = 10;
i += 0; // gives back the same object.

但是,如果对象没有被池化

Double d = 10;
d += 0; // creates a new object.
<小时/>
var.notify();

尝试对新对象(而不是已锁定的对象)调用notify

<小时/>

您不应该尝试锁定您变异的字段。它不会做它看起来做的事情。您也不应该锁定池对象。在这种情况下,您可以让另一个线程使用相同的 Integer 来实现不相关的目的,并且 notify() 将唤醒一个不相关的线程。

要正确使用等待/通知,您应该

  • notify()notifyAll() 在另一个共享字段中发生状态更改后。
  • 您应该使用 while 循环进行 wait() 来检查状态更改。

如果你不这样做

  • 如果另一个线程没有等待,notify 可能会丢失。
  • 即使没有调用任何通知,wait 也可能会被虚假唤醒。

For the above requirement what is the edit suggested in the code? How do i share the same object for multiple threads?

public class PingPong implements Runnable {    
    static class Shared { int num; }

    private final Shared var;
    private final int bit;

    public static void main(String[] args) {
        Shared var = new Shared();
        new Thread(new PingPong(var, 0), "EvenThread").start();
        new Thread(new PingPong(var, 1), "OddThread").start();
    }

    PingPong(Shared var, int bit) {
        this.var = var;
        this.bit = bit;
    }

    @Override
    public void run() {
        try {
            String name = Thread.currentThread().getName();
            while (true) {
                synchronized (var) {
                    while (var.num % 2 == bit)
                        var.wait();

                    var.num++;
                    System.out.println(name + "  " + var.num);
                    var.notify();
                }
            }
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
        }
    }
}

关于java等待并通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36566571/

相关文章:

iOS swift后台线程阻塞主线程

c++ - 使用 std::thread 暂停/恢复异步进程

javascript - 加载图像后重定向

java - 为什么这个字符串比较器无法编译?

java - JSF2.0 部分渲染与 ui :define

java - 检查字符串中是否有单词后跟数字

java - 自定义字体未应用

c - 从C中的不同线程读取文件

python - 如何等到 Python 中存在目录(Ubuntu)

java - 顺序等待语句