How to use wait() and notify() in Java?

送分小仙女□ 提交于 2019-12-04 10:13:14
Thufir Hawat

You must add the mutex reference to wait() and notify(); that is, change wait() to mutex.wait() and notify() to mutex.notify().

Without this, you are calling to wait/notify on this (method() is equivalent to this.method())

Here is your code with the appropriate changes made:

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

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. As a result, the first thread will stay in mutex.wait() forever.

Second, wait() / notify() are not thought to be used as thread-handshake-mechanism directly. This could only work if you could guarantee that the first thread calls wait() before the second thread calls notify(). Usually, you can't.

Instead, wait() should be used to wait for a certain condition to become true. The condition is usually changed by another thread, who notifies the waiting thread by calling notifyAll(). So the handshake-mechanism is the condition, not 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! 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().

Using wait()/notifyAll()

So in your case, you could use wait() and notifyAll() in combination with a 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();
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!