wait() sleep() notify() notifyAll()
1、wait()、sleep() 方法相同点
(1)都是对线程的操作;
(2)都需要抛异常; (这一点我遇到很多人答错,记住这两者都会抛异常)
(3)都会让当前运行线程进入阻塞状态。
(4)都能在阻塞过程中感受到中断信号。
2、wait()、sleep() 方法不同点
(1)使用位置不同: wait() 方法必须在synchronized 同步代码中,sleep() 则不需要;
(2)申明位置不同: wait() 方法是 Object类 中的方法,sleep() 方法是 Thread类中的静态方法;
(3)调用时是否释放锁不同:wait() 调用时线程是要释放同步监视器(锁)的,sleep() 不会释放同步监视器(锁);
(4)wait() 方法要结合 notify() 方法或者 notifyAll() 方法一起使用,不然就会一直阻塞线程。(没有设置时间的情况下)
(5)sleep() 方法是必须要求指定一个时间,超时之后就会恢复操作,而 wait() 方法如果没有设置时间的话,会一直处于等待状态,只有等到被唤醒或者被中断才会恢复。
重点说明一下:
1、wait() 是和 synchronized 锁一起使用,而 await() 是和 Lock 锁一起使用,await() 方法是 Condition 接口中的方法;
2、wait() 为什么必须在 synchronized 同步代码中使用呢 ?
主要原因是为了程序的安全性,必须保证每一个线程持有锁之后的操作都是原子的,不然可能会带来线程之间的通信失败。比如说本来现在是应该阻塞当前线程,由于不是原子的,这时候要是没有阻塞这个线程,那么此时要是执行到要去唤醒刚刚没有被阻塞的那个线程就是不对的。
另外 wait() 方法是会释放锁的,要是不是原子的,第一个线程还没有执行到 wait() 方法,也就是还没有释放当前锁,此时另外一个线程就开始执行显然是不会持有锁的,那么会报IllegalMonitorStateException异常的。
3、为什么会把 wait() 方法定义在 Object类中,sleep() 方法定义在 Thread类中 ?(我的理解是:)
我们都知道,Object 类是所有对象的父类,另外加锁加锁其实就是给对象进行加锁,那么 wait()、notify()、notifyAll()定义在 Object 这个对象父类中就是理所当然的了,而不是 Thread 线程类中;
如果把wait() 、notify()、notifyAll() 方法定义在 Thread 类中,我们就不好让一个线程持有对象锁(非同一时刻),又不好确定线程等待的是哪一把锁?既然是线程等待某一个对象的锁,那么操作对象是最为合适的,而不是线程;
另外:每一个对象的对象头 markword 里都会有锁状态信息,也就是用此来表示对象的锁状态,是无锁、偏向锁、轻量级锁、重量级锁呢?而不是在每一个线程里。想了解对象的对象头 markword 或者 synchronized 的锁膨胀机制,可以看这里。
3、notify() 方法和 notifyAll() 方法
(1)notify() 方法和 notifyAll() 方法是Object类中定义的方法;
(2)notify() 方法:
①线程不能一直在等待集合中,必须有方法对其进行唤醒,notify() 方法可以对线程进行唤醒;
②使用 this 作为当前对象的引用,故可以直接写成 notify() 进行调用,而不必用当前对象点上 notify() 方法;(这一点下面Demo中
有演示)
③当使用某个对象的 notify() 方法时,将从该对象的等待集合中任意选择一个等待的线程唤醒,唤醒的线程将从等待集合中删除。
(3)notifyAll()方法:
①notifyAll() 方***将所有在等待集合中的线程唤醒;
②由于所有的被唤醒的线程仍然要去争用synchronized锁,而synchronized锁具有排他性,最终只有一个线程获得该锁,进行执行状态,其他线程仍要继续等待,只是现在被唤醒的这些线程都有去抢夺同步监视器(锁)的权利了。