在多线程中,线程的等待和唤醒已知的有两种:
- 1.使用object的wait方法让线程等待,然后使用object的notify方法唤醒线程
- 2.使用juc包中Condition的await()方法让线程等待,使用signal()方法唤醒线程
使用Object类中的方法实现线程等待和唤醒
public static void testWaitAndNotify() throws InterruptedException {
new Thread(()-> {
System.out.println(Thread.currentThread().getName() + "============>start");
synchronized (lock) {
System.out.println("lock===============>");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end lock=================>");
}
},"t1").start();
TimeUnit.SECONDS.sleep(5);
synchronized (lock) {
lock.notify();
System.out.println("notify======================>");
}
}
t1线程中调用 lock.wait()方法让t1线程等待,主线程中休眠5秒之后,调用 lock.notify()方法唤醒了t1线程,输出的结果中,两行结果相差5秒左右,程序正常退出。
如果notify方法在wait方法之前,会有什么效果
public static void testWaitAndNotify1() throws InterruptedException {
new Thread(()-> {
System.out.println(Thread.currentThread().getName() + "============>start");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
System.out.println("lock===============>");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end lock=================>");
}
},"t1").start();
TimeUnit.SECONDS.sleep(1);
synchronized (lock) {
lock.notify();
System.out.println("notify======================>");
}
}
输出了上面2行之后,程序一直无法结束,t1线程调用wait()方法之后无法被唤醒了,从输出中可见, notify()方法在 wait()方法之前执行了,等待的线程无法被唤醒了。说明:唤醒方法在等待方法之前执行,线程无法被唤醒。
关于Object类中的用户线程等待和唤醒的方法,总结一下:
- 1.wait()/notify()/notifyAll()方法都必须放在同步代码(必须在synchronized内部执行)中执行,需要先获取锁
- 2.线程唤醒的方法(notify、notifyAll)需要在等待的方法(wait)之后执行,等待中的线程才可能会被唤醒,否则无法唤醒
使用Condition实现线程的等待和唤醒
public static void testCondition() throws InterruptedException {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "==============> start");
REENTRANT_LOCK.lock();
try {
System.out.println("==================== wait start");
CONDITION.await();
System.out.println("==================== wait end");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("解锁==========>" + Thread.currentThread().getName());
REENTRANT_LOCK.unlock();
}
}, "condition").start();
TimeUnit.SECONDS.sleep(5);
REENTRANT_LOCK.lock();
try {
CONDITION.signal();
} finally {
System.out.println("解锁==========>" + Thread.currentThread().getName());
REENTRANT_LOCK.unlock();
}
}
关于Condition中方法使用总结:
- 使用Condtion中的线程等待和唤醒方法之前,需要先获取锁。否者会报 IllegalMonitorStateException异常
- signal()方法先于await()方法之前调用,线程无法被唤醒
Object和Condition的局限性
程等待和唤醒的方法能够执行的先决条件是:线程需要先获取锁
唤醒方法需要在等待方法之后调用,线程才能够被唤醒
LockSupport在下篇介绍