线程通讯——wait和sleep的区别
线程通讯
协调线程通讯,主要涉及三个方法:
wait()/wait(long timeout):让当前线程进入等待状态
notify():唤醒当前对象上一个休眠的线程
notifyAll():唤醒当前对象上的所有线程
线程通讯注意事项:
- wait/notify/notifyAll 必须要配合synchronized 一起执行。
- wait/notify/notifyAll 进行synchronized 加锁,一定要使用同一个对象进行加锁。
- 当调用了notify/notifyAll 之后,程序并不会立即恢复执行,而是尝试获取锁,只有得到锁之后才能继续执行。
- notifyAll 并不是唤醒所有 wait 等待的线程的,而是唤醒当前对象处于 wait 等待的所有线程。
第四点举例:
public class ThreadNotifyAll2 {
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Object lock2 = new Object();
Thread thread1 = new Thread(()->{
synchronized (lock){
System.out.println("开始执行线程1");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1被唤醒");
}
},"线程1");
thread1.start();
Thread thread2 = new Thread(()->{
synchronized (lock2){
System.out.println("开始执行线程2");
try {
lock2.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2被唤醒");
}
},"线程2");
thread2.start();
Thread thread3 = new Thread(()->{
synchronized (lock){
System.out.println("开始执行线程3");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程3被唤醒");
}
},"线程3");
thread3.start();
Thread.sleep(1000);
System.out.println("唤醒全部线程");
synchronized(lock){
lock.notifyAll();
}
}
}
从运行结果可以看出线程2没有被唤醒,因为 notifyAll 并不是唤醒所有 wait 等待的线程的,而是唤醒当前对象(lock)处于 wait 等待的所有线程。
wait 和sleep 的区别
相同点:
- 两者都是可以让线程进入休眠状态。
- 两者都可以相应Interrupte(中断)状态
不同点:
- wait 必须配合synchronized 一起使用,而sleep不需要;
- wait 属于Object(对象)的方法,而sleep属于Thread (线程)的方法;
- wait 释放锁,sleep 不释放锁;
- wait 有可能无限等待下去,sleep 有明确的终止等待时间(即wait 可以不传参数,sleep 必须要传递一个数值类型的参数);
- sleep 和 wait 产生的线程状态不同,wait 方法让线程进入WAITING状态,而sleep 方法让线程进入TIME_WAITING状态;
- 一般情况下,sleep 只能等待超时时间之后在恢复执行,而wait 可以接受notify /notifyAll 之后就绪执行。