简介
wait()
、notify()
方法可用于控制线程的生命周期
详解
1、wait() 不带参数
在 当前线程 中调用 A对象 的
wait()
方法,此时 当前线程 会进入 等待状态,此时 当前线程 会释放所持有的 锁资源,等到 其它线程 调用 A对象 的notify()
或者notifyAll()
进行唤醒,当前线程 才有可能重新拿到 锁资源 并继续执行。
a、调用 wait() 与 notify() 的不是同一个对象-错误
/**
* 调用 wait()、notify() 的不是同一个对象
*/
public class WaitDetail01Main {
public static void main(String[] args) {
WaitDetail01 t1 = new WaitDetail01();
WaitDetail01 t2 = new WaitDetail01();
t1.setFlag(true);
t2.setFlag(false);
t1.setName("A");
t2.setName("B");
t1.start();
t2.start();
}
}
class WaitDetail01 extends Thread{
static Object o1 = new Object();
private boolean flag;
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if(flag){
synchronized (this){
try {
// 当前 this 为 A线程对象
// 线程B对象调用 notify() 不会唤醒 线程A
// 一直等待
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程 " + Thread.currentThread().getName() + " 进入 1...");
}
}else{
// B线程
synchronized (this){
System.out.println("线程 " + Thread.currentThread().getName() + " 进入 2...");
// 当前 this 为 线程B对象
this.notify();
}
}
}
}
解析:调用 wait()
和 notify()
的必须是 同一个对象
b、当前线程未持有锁对象,去调用 wait()、notify()-错误
/**
* 当前线程未持有锁,去调用 wait()、notify()
*/
public class WaitDetail02Main {
public static void main(String[] args) {
WaitDetail02 t1 = new WaitDetail02();
WaitDetail02 t2 = new WaitDetail02();
t1.setFlag(true);
t2.setFlag(false);
t1.setName("A");
t2.setName("B");
t1.start();
t2.start();
}
}
class WaitDetail02 extends Thread{
static Object o1 = new Object();
private boolean flag;
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if(flag){
try {
// A线程
// 未持有 o1 锁对象,调用 wait()
// 抛出 IllegalMonitorStateException
o1.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1){
System.out.println("线程 " + Thread.currentThread().getName() + " 进入 1...");
}
}else{
// B线程
// 未持有 o1 锁对象,调用 notify()
// 抛出 IllegalMonitorStateException
o1.notify();
synchronized (o1){
System.out.println("线程 " + Thread.currentThread().getName() + " 进入 2...");
}
}
}
}
解析:在当前线程中调用 wait()
、notify()
方法之前,必须保证当前线程 此时 已经持有了 锁对象,否则抛出 IllegalMonitorStateException
2、wait() 带参数
wait(long timeout)
带一个参数:指定一个超时时间,在 当前线程 中调用 A对象 的wait(50)
方法,此时 当前线程 会进入 等待状态,此时 当前线程 会释放所持有的 锁资源,等到 50毫秒 时间到了之后,自动被唤醒,才有可能重新拿到 锁资源 并继续执行。
a、wait() 带参数-正确
/**
* wait() 带参数
*/
public class WaitDetail03Main {
public static void main(String[] args) {
WaitDetail03 t1 = new WaitDetail03();
WaitDetail03 t2 = new WaitDetail03();
t1.setFlag(true);
t2.setFlag(false);
t1.setName("A");
t2.setName("B");
t1.start();
t2.start();
}
}
class WaitDetail03 extends Thread{
static Object o1 = new Object();
static Object o2 = new Object();
private boolean flag;
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if(flag){
synchronized (o1){
try {
// 等待 50 毫秒后 自动唤醒
// 50 毫秒后,B线程已经执行完毕并释放了锁资源 o1
// 此时 线程A 被自动唤醒,并重新获取锁资源 o1
o1.wait(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程 " + Thread.currentThread().getName() + " 进入 1...");
}
}else{
synchronized (o1){
System.out.println("线程 " + Thread.currentThread().getName() + " 进入 2...");
}
}
}
}
解析:wait()
带参数的方法不需要满足:wait()
与 notify()
的调用者是同一个对象,因为它不会 显示调用 notify()
;但还是必须满足:在当前线程中调用 wait()
带参数的方法之前,必须保证当前线程 此时 已经持有了 锁对象,否则抛出 IllegalMonitorStateException
3、notify()
随机唤醒某个因为执行了
wait()
方法而在 等待区 等待的线程
4、notifyAll()
唤醒所有因为执行了
wait()
方法而在 等待区 等待的线程