简体   繁体   English

如何在Java中使用wait()和notify()?

[英]How to use wait() and notify() in Java?

As I understand, I am suppose to call wait() on the mutex, when I want the current thread to stop working until another thread calls notify() on the same mutex object. 据我所知,我想在互斥锁上调用wait(),当我希望当前线程停止工作,直到另一个线程在同一个互斥对象上调用notify()。 That doesn't seem to be working. 这似乎不起作用。

I'm trying to make a thread print 1-10. 我正在尝试打印线程1-10。 Then wait for another thread to print 11-20. 然后等待另一个线程打印11-20。 And then the first thread would again print 21-30 然后第一个线程将再次打印21-30

Main.java Main.java

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Object mutex = 1;

        Thread child1 = new Thread(new Child1(mutex));
        Thread child2 = new Thread(new Child2(mutex));

        child1.start();
        child2.start();

    }

}

Child1.java Child1.java

public class Child1 implements Runnable {
    Object mutex;

    public Child1(Object mutex){
        this.mutex = mutex;
    }

    public void run() {
        synchronized (mutex) {
            for(int c = 0; c < 10; c++){
                System.out.println(c+1);
            }

            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }


        for(int c = 20; c < 31; c++){
            System.out.println(c+1);
        }
    }
}

Child2.java Child2.java

public class Child2 implements Runnable {
    Object mutex;

    public Child2(Object mutex) {
        this.mutex = mutex;
    }

    public void run() {
        synchronized (mutex) {
            for (int c = 11; c < 21; c++) {
                System.out.println(c);
            }
            notify();
        }

    }
}

Output 产量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17Exception in thread "Thread-0" 
18
19
20
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at task42.Child1.run(Child1.java:18)
    at java.lang.Thread.run(Thread.java:745)
java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at task42.Child2.run(Child2.java:15)
    at java.lang.Thread.run(Thread.java:745)

What am I missing? 我错过了什么?

You must add the mutex reference to wait() and notify() ; 您必须将mutex引用添加到wait()notify() ; that is, change wait() to mutex.wait() and notify() to mutex.notify() . 也就是说,将wait()更改为mutex.wait()并将notify()更改为mutex.notify()

Without this, you are calling to wait/notify on this ( method() is equivalent to this.method() ) 没有这一点,您呼叫等待/通知对thismethod()是等效于this.method()

Here is your code with the appropriate changes made: 以下是您的代码,并进行了相应的更改:

Child1.java Child1.java

public class Child1 implements Runnable {
    Object mutex;

    public Child1(Object mutex){
        this.mutex = mutex;
    }

    public void run() {
        synchronized (mutex) {
            for(int c = 0; c < 10; c++){
                System.out.println(c+1);
            }

            try {
                mutex.wait(); // Changed here
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }


        for(int c = 20; c < 31; c++){
            System.out.println(c+1);
        }
    }
}

Child2.java Child2.java

public class Child2 implements Runnable {
    Object mutex;

    public Child2(Object mutex) {
        this.mutex = mutex;
    }

    public void run() {
        synchronized (mutex) {
            for (int c = 11; c < 21; c++) {
                System.out.println(c);
            }
            mutex.notify(); // Changed here
        }

    }
}

Your code fails in several ways. 您的代码在几个方面失败。

First of all, there is no guarantee, that the first thread will also run first. 首先,不能保证第一个线程也会先运行。 (Especially on multi-cores, there is a high chance, that both run in parallel). (特别是在多核上,很有可能两者并行运行)。 So if the second thread enteres the synchronized block of Child2.run() first, it will call mutex.notify() even before the first thread is in wait state. 因此,如果第二个线程首先进入Child2.run()synchronized块,它将在第一个线程处于等待状态之前调用mutex.notify() As a result, the first thread will stay in mutex.wait() forever. 结果,第一个线程将永远保留在mutex.wait()

Second, wait() / notify() are not thought to be used as thread-handshake-mechanism directly. 其次, wait() / notify()不被认为直接用作线程握手机制。 This could only work if you could guarantee that the first thread calls wait() before the second thread calls notify() . 只有在第二个线程调用notify() 之前可以保证第一个线程调用wait() 这才有效。 Usually, you can't. 通常,你不能。

Instead, wait() should be used to wait for a certain condition to become true. 相反,应使用wait()等待某个条件变为true。 The condition is usually changed by another thread, who notifies the waiting thread by calling notifyAll() . 该条件通常由另一个线程更改,该线程通过调用notifyAll()通知等待线程。 So the handshake-mechanism is the condition, not wait / notify : 所以握手机制是条件,而不是wait / notify

// 1st thread:
synchronized (lock) {
    while (!condition) {
        lock.wait();
    }
    // continue
}

// 2nd thread:
synchronized {
    condition = true;
    lock.notifyAll();
}

Any other usage-pattern of wait() / notify() or notifyAll() is wrong! wait() / notify()notifyAll()任何其他用法模式都是错误的! It is also very important to always call wait() inside a loop as a thread might wake up on chance - even without notify() or notifyAll() . 始终在循环内调用wait()也是非常重要的,因为线程可能会偶然唤醒 - 即使没有notify()notifyAll()

Using wait()/notifyAll() 使用wait()/notifyAll()

So in your case, you could use wait() and notifyAll() in combination with a stage-variable: 因此,在您的情况下,您可以将wait()notifyAll()与stage-variable结合使用:

public class Mutex {
    static final Object lock = new Object();
    static int stage = 1;

    static void first() throws InterruptedException {
        synchronized (lock) {
            // we're already in stage 1
            for(int i = 0; i < 10; ++i) System.out.println(i);

            // enter stage 2
            stage = 2;
            lock.notifyAll();

            // wait for stage 3
            while (stage != 3) { lock.wait(); }

            // now we're in stage 3
            for(int i = 20; i < 30; ++i) System.out.println(i);
        }
    }

    static void second() throws InterruptedException {
        synchronized (lock) {
            // wait for stage 2
            while (stage != 2) { lock.wait(); }

            // now we're in stage 2
            for(int i = 20; i < 30; ++i) System.out.println(i);

            // enter stage 3
            stage = 3;
            lock.notifyAll();
        }
    }

    public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    Mutex.first();
                } catch (InterruptedException ex) { }
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                try {
                    Mutex.second();
                } catch (InterruptedException ex) { }
            }
        }).start();
    }
}

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

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