简体   繁体   English

java等待并通知

[英]java wait and notify

I'm taking one Integer variable and sharing with two threads. 我正在使用一个Integer变量并与两个线程共享。 One thread should print even numbers and one thread should print odd number sequentially. 一个线程应顺序打印偶数,一个线程应顺序打印奇数。 But notify() throwing IllegalMonitorStateException. 但是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();
            }
        }
    }
}

And the output is : 输出为:

OddThread 1 奇数线程1

Exception in thread "OddThread" java.lang.IllegalMonitorStateException

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

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

I think this is sufficiently different to the usual answer to give another one. 我认为这与通常的答案足够不同,可以再给出一个答案。

In this case you are using synchronized . 在这种情况下,您正在使用synchronized When you apply a lock it is on a object not a reference. 当您应用锁时,它是在对象而不是引用上。


synchronized (var) {

This locks the object var references, not on var as a field. 这种锁定对象var引用,而不是var作为一个字段。


var++;

This replaces the object var points to. 这将替换对象var指向的对象。 It is the same as 与...相同

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

Note: Integer and indeed all the primitive wrappers are Immutable. 注意: Integer以及实际上所有原始包装器都是不可变的。 When you perform any operation on them you are actually unboxing, calculating using the primitive value and re-boxing the object. 当您对它们执行任何操作时,您实际上是在拆箱,使用原始值进行计算并重新装箱该对象。 It is possible to get the same object back if it is pooled. 如果将同一对象合并,则可以将其取回。 eg 例如

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

However, if the object is not pooled 但是,如果未合并对象

Double d = 10;
d += 0; // creates a new object.

var.notify();

Attempts the call notify on the new object, not the one which was locked. 尝试调用notify新对象,而不是锁定的对象。


You shouldn't attempt to lock a field which you mutate. 您不应尝试锁定您突变的字段。 It won't do what it appears to do. 它不会做看起来像做的事情。 You also shouldn't lock on a pooled object. 您也不应该锁定池对象。 In this case you could have another thread using the same Integer for an unrelated purpose and notify() will wake up an unrelated thread. 在这种情况下,您可能有另一个线程将同一Integer用于不相关的目的,并且notify()将唤醒不相关的线程。

To use wait/notify correctly, you should 要正确使用等待/通知,您应该

  • notify() or notifyAll() after a state change in another shared field. 其他共享字段中的状态更改后, notify()notifyAll()
  • you should use a while loop for wait() to check the state change. 您应该对wait()使用while循环来检查状态更改。

If you don't do this 如果你不这样做

  • notify can be lost if another thread is not waiting. 如果另一个线程没有等待,则通知可能会丢失。
  • wait can wake spuriously, even when no notify was called. 即使没有调用通知,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");
        }
    }
}

Instead of using Integer wrapper class,I created my own class and now It works fine. 我没有使用Integer包装器类,而是创建了自己的类,现在它可以正常工作。

 package mywaitnotifytest; public class App { public static void main(String[] args) { MyInt i = new MyInt(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 { MyInt var; Even(MyInt var) { this.var = var; } @Override public void run() { while (true) { try { Thread.sleep(200); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } synchronized (var) { if (var.i % 2 == 0) { try { var.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } var.i++; System.out.println(Thread.currentThread().getName() + " " + var.i); var.notify(); } } } } class Odd extends Thread { MyInt var; Odd(MyInt var) { this.var = var; } @Override public void run() { while (true) { try { Thread.sleep(2000); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } synchronized (var) { if (var.i % 2 != 0) { try { var.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } var.i++; System.out.println(Thread.currentThread().getName() + " " + var.i); var.notify(); } } } } class MyInt { int i = 0; public MyInt(int i) { super(); this.i = i; } @Override public String toString() { // TODO Auto-generated method stub return "" + i; } } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM