目录
[2)wait(long timeout)带参数](#2)wait(long timeout)带参数)
3)其他线程调⽤该等待线程的interrupted⽅法,?导致wait抛出 InterruptedException 异常.其他线程调⽤该等待线程的interrupted⽅法,?导致wait抛出 InterruptedException 异常.)
前言:
线程是抢占式执行的,无法预知线程之间的执行顺序。线程是随机调度。
但有时程序员也希望能合理协调多个线程的执行顺序。
因此,在 Java 中使用了等待(wait)和通知(notify)机制,用于在应用层面上干预多个线程的执行顺序。
完成这个协调⼯作, 主要涉及到三个⽅法
- wait() / wait(long timeout): 让当前线程进⼊等待状态.
- notify() / notifyAll(): 唤醒在当前对象上等待的线程.
注意:wait,notify,notifyAll都是Object类的方法
1.wait方法
• 使当前执⾏代码的线程进⾏等待.(把线程放到等待队列中)
• 释放当前的锁
• 满⾜⼀定条件时被唤醒,重新尝试获取这个锁.
wait要搭配synchronized来使⽤.脱离synchronized使⽤wait会直接抛出异常.
代码⽰例:观察wait()⽅法使⽤:
wait结束等待的条件:
1)wait()不带参数
java
public class demo4 {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
synchronized (object) {
System.out.println("等待中");
object.wait();
System.out.println("等待结束");
}
}
}
这样在执⾏到object.wait()之后就⼀直等待下去,那么程序肯定不能⼀直这么等待下去了
2)**wait(long timeout)**带参数
java
public class demo4 {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
synchronized (object) {
System.out.println("等待中");
object.wait(1000);
System.out.println("等待结束");
}
}
}
java
等待中
等待结束
Process finished with exit code 0
3)其他线程调⽤该等待线程的interrupted⽅法,?导致wait抛出 InterruptedException 异常.
java
public class demo4 {
public static void main(String[] args) {
//创建锁对象;
Object locker = new Object();
Thread t1 = new Thread(() -> {
System.out.println("wait前");
//在 synchronized 代码块中调用 wait 方法;
synchronized (locker) {
// wait 方法是由锁对象调用的,调用后,线程释放锁,进入等待队列;
try {
locker.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("wait后");
});
t1.start();
//抛出异常,清除中断标志,唤醒t1线程。
t1.interrupt();
}
}
4)使用notify方法唤醒
2.notify()方法
notify⽅法是唤醒等待的线程.
- ⽅法notify()也要在同步⽅法或同步块中调⽤,该⽅法是⽤来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
- 如果有多个线程等待,则有线程调度器随机挑选出⼀个呈wait状态的线程。(并没有"先来后到")
- 在notify()⽅法后,当前线程不会⻢上释放该对象锁,要等到执⾏notify()⽅法的线程将程序执⾏完,也就是退出同步代码块之后才会释放对象锁。
notify()⽅法
java
public class demo4 {
public static void main(String[] args) {
//创建锁对象;
Object locker = new Object();
Thread t1 = new Thread(()->{
System.out.println("t1 wait前!");
synchronized (locker) {
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t1 wait后!");
});
Thread t2 = new Thread(()-> {
try {
Thread.sleep(1000);
System.out.println("t2 notify 之前");
//让 t1 线程有时间进入到wait状态
synchronized (locker) {
locker.notify();
System.out.println("t2 notify 之后");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
t1.start();
t2.start();
}
}
java
t1 wait前!
t2 notify 之前
t2 notify 之后
t1 wait后!
Process finished with exit code 0
notifyAll()⽅法
使用notifyAll()⽅法可以唤起所有的线程
java
public static void main(String[] args) throws InterruptedException {
Object locker = new Object();
Thread t1 = new Thread(()->{
System.out.println("t1 wait!");
synchronized (locker) {
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t1 over!");
});
Thread t2 = new Thread(()->{
System.out.println("t2 wait!");
synchronized (locker) {
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t2 over!");
});
Thread t3 = new Thread(()->{
System.out.println("t3 wait!");
synchronized (locker) {
try {
locker.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t3 over!");
});
Thread t4 = new Thread(()->{
synchronized (locker) {
System.out.println("t4 唤起所有线程");
locker.notifyAll();
}
});
t1.start();
t2.start();
t3.start();
Thread.sleep(1000);
t4.start();
}
添加
Thread.sleep(1000)
后,程序会稍微暂停 1 秒钟,确保t1
、t2
和t3
线程已经进入wait()
方法并且已经释放了locker
锁。这样,在t4
线程调用notifyAll()
时,locker
锁已经被释放,t4
可以成功获取锁并调用notifyAll()
来唤醒所有等待的线程,从而避免了死锁。
3.wait和sleep的对⽐(⾯试题)
特性 | wait() |
sleep() |
---|---|---|
来源 | Object 类的实例方法 |
Thread 类的静态方法 |
锁的释放 | 会释放对象锁 | 不释放锁 |
线程状态 | 进入等待状态(Waiting) | 进入休眠状态(Sleeping) |
使用场景 | 线程间通信与协调(如生产者-消费者) | 控制线程暂停时间、模拟延时等 |
中断处理 | 抛出 InterruptedException |
抛出 InterruptedException |
参数 | 可以指定等待时间(毫秒、纳秒) | 可以指定休眠时间(毫秒、纳秒) |
是否需要同步 | 需要在同步代码块或同步方法中调用 | 不需要同步 |
影响线程调度 | 影响线程的调度,直到线程被唤醒 | 影响线程调度,直到指定时间过后 |
线程恢复 | 通过 notify() 或 notifyAll() 唤醒 |
休眠时间到达后自动恢复 |
总结:
调用对象 :
wait()
是Object
类的一个方法,它必须在同步块或同步方法中调用,用于释放当前线程持有的锁,并使线程进入等待队列,直到其他线程调用同一对象的notify()
或notifyAll()
方法。而sleep()
是Thread
类的静态方法,线程调用时不需要持有锁,它会让当前线程休眠指定的时间。释放锁 :
wait()
会释放对象的锁,而sleep()
不会释放锁。目的 :
wait()
主要用于线程间的通信,线程进入等待状态直到被唤醒;sleep()
主要用于控制线程的暂停时间,通常不用于线程间的协调。
结语: 写博客不仅仅是为了分享学习经历,同时这也有利于我巩固知识点,总结该知识点,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进。同时也希望读者们不吝啬你们的点赞+收藏+关注,你们的鼓励是我创作的最大动力!