wait和notify
标签:Java并发

wait和notify

如果一个线程调用了 Object.wait() ,那么它就会进入对象的等待队列中。这个等待队列中,可能会有多个线程,因为系统运行多个线程同时等待某一个对象。

当调用 object.notify()被调用时,它就会从这个等待队列中,随机选择一个线程,并将其唤醒。

在调用wait()方法之前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步块中才能调用wait()方法。在执行wait()方法之后,当前线程释放锁。在从 wait()方法返回前,线程与其他线程竞争重新获得锁。如果调用 wait()方法没有获取持有适当的锁,将会抛出 IllegalMonitorStateException

方法 notify也要在同步方法或同步块中调用,即在调用前,也要持有适当的锁,如果没有的话,也会抛出 IllegalMonitorStateException

注意:在执行完 notify()方法后,当前线程不会马上释放该对象锁,wait()状态的线程也不能马上获取该对象锁,要等到 notify()线程将程序执行完后,也就是退出同步方法之后,当前线程才会释放锁,wait()状态的线程才可以获取到锁。


简单例子:

public class SimpleWN {
    final static Object OBJECT=new Object();
    public static class T1 extends Thread{
        @Override
        public void run() {
            synchronized (OBJECT){
                System.out.println("T1 start:"+System.currentTimeMillis());
                try {
                    OBJECT.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("T1 end:"+System.currentTimeMillis());
            }
        }
    }

    public static class T2 extends Thread{
        @Override
        public void run() {
            synchronized (OBJECT){
                System.out.println("T2 start:"+System.currentTimeMillis());
                OBJECT.notify();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("T2 end:"+System.currentTimeMillis());
            }
        }
    }

    public static void main(String[] args) {
        new T1().start();
        new T2().start();
    }
}

输出:

T1 start:1534924644721
T2 start:1534924644721
T2 end:1534924646721
T1 end:1534924646721

wait和sleep

Object.wait()Thread.sleep()方法都可以让线程等待若干时间,除了wait方法可以被唤醒以外。另一个主要区别是wait方法会释放目标对象的锁,而sleep方法不会释放任何资源。

这里也说一下,suspend方法在暂停线程的时候,也会不释放任何资源,需要等到resume方法被执行,如果resume方法发生意外而没有被执行或者先于suspend执行的话,那么执行了suspend方法先线程将会被永久挂起,而起状态显示还是Runnable的,这样也会影响我们对线程状态的判断,故不能使用suspendresume来暂停和恢复线程。

  • 2 min read

CONTRIBUTORS


  • 2 min read