文章目录
- wait() 一定需要notify()唤醒吗?
- 正常情况
- 线程对象为锁资源时
wait() 一定需要notify()唤醒吗?
本质上都是通过notify()(通知)来唤醒的。也就是说等待的线程一定要被通知才会醒的!只是处罚的途径不同。
一般也就两种情况:
- 正常情况下的等待、唤醒,是要用notify()来唤醒的。
- 当线程执行完之后,被等待的线程会在退出前调用notifyAll()方法通知所有的等待线程继续执行。
《下面内容摘抄自《实战Java高并发程序设计2》2.2节。》
正常情况
正常情况很简单,也就是wait()与notify()方法的使用。关于两个方法的详解可看:线程的基本操作(全)
直接看案例:
线程T1调用临界区资源OBJECT的wait()方法,进入这个资源对象的等待队列中,等待唤醒
线程T2调用临界区资源OBJECT的notify()方法,唤醒了线程T1。
package com.wlw.test;
public class testThread {
// 临界区资源
public static final Object OBJECT = new Object();
public static class T1 extends Thread {
@Override
public void run() {
// 锁
synchronized (OBJECT) {
System.out.println("T1 start.");
try {
System.out.println("T1 wait for object");
// 等待
OBJECT.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T1 end.");
}
}
}
public static class T2 extends Thread {
@Override
public void run() {
// 锁
synchronized (OBJECT) {
System.out.println("T2 start.");
// 唤醒
OBJECT.notify();
System.out.println("T2 notify for object");
try {
// 模拟代码执行,休眠1s
Thread.sleep(1000);
System.out.println("T2 sleep 1s.");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T2 end.");
}
}
}
public static void main(String[] args) {
T1 t1 = new T1();
T2 t2 = new T2();
t1.start();
t2.start();
}
}
执行结果:
T1 start.
T1 wait for object
T2 start.
T2 notify for object
T2 sleep 1s.
T2 end.
T1 end.
线程对象为锁资源时
这里用到了Thread.join()方法。join()方法为加入的意思。在A线程中执行B线程的join()方法,A会等待B执行完之后,再继续执行。
看案例:
package com.wlw.test;
public class testThread {
public volatile static int i = 0;
public static class T1 extends Thread {
@Override
public void run() {
for (i = 0; i < 100000; i++) {
}
}
}
public static void main(String[] args) throws InterruptedException {
T1 t1 = new T1();
t1.start();
// 等待t1线程执行完
t1.join();
System.out.println(i);
}
}
在主函数中,如果不使用join()方法等待T1线程,那么得到的i很可能是0或者一个非常小的数字。因为T1还没开始执行,i的值就已经被输出了。但在使用join()方法后,表示主线程愿意等待T1执行完毕,跟着T1一起往前走,故在join()方法返回时,T1已经执行完成,因此i总是100000。
此时我们来看下join()方法的源码:
package java.lang;
public class Thread implements Runnable {
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
}
注意这一行代码:
if (millis == 0) {
while (isAlive()) {
wait(0);
}
}
join()方法的本质是让调用线程wait()方法在当前线程对象实例上。
即它让调用线程在当前线程对象上进行等待。当线程执行完成后,被等待的线程会在退出前调用notifyAll()方法通知所有的等待线程继续执行。因此,值得注意的一点是:不要在应用程序中,在Thread对象实例上使用类似wait()方法或者notify()方法等,因为这很有可能会影响系统API的工作,或者被系统API所影响。
所以建议:线程间的等待唤醒机制,最好不要用线程对象做同步锁!