线程间协作
1. 等待和通知
等待和通知的标准形式
等待方:
- 获取对象锁
- 循环中判断条件是否满足,不调用wait()方法
- 条件满足执行业务逻辑
通知方:
- 获取对象所
- 改变条件
- 通知所有等待在对象的线程
2. wait、notify/notifyAll
wait:导致当前线程等待,直到有其他线程调用当前同步监视器的notify()
或notifyall()
方法来唤醒此线程。wait()
方法有三种形式——无时间参数的wait(一直等待,直到其他线程通知),带毫秒参数的waut()和带毫秒和纳秒参数的wait(指定时间后自动苏醒)
notify:唤醒在此同步监视器上等待的单个线程,如果有多个线程在此同步监视器上等待,那么只会随机的呼唤其中的一个线程;等待的线程只是被激活,但是必须得再次获得锁才能继续往下执行,也就是说只要锁没被释放,原等待线程因为为获取锁仍然无法继续执行。
notifyAll:唤醒所有等待在此同步监视器上的线程,所有线程处于激活状态。
wait()方法、notify()方法和notiftAll()方法来自于
java.lang.Object
,用于协调多线程对共享数据的存取,所以只能在同步方法或者同步块中使用,否则抛出异常(IllegalMonitorStateException)。
3. join
Thread 提供了一个让一个线程等待另一个线程执行完成的方法——join()方法;当程序执行中调用其它线程的join()方法时,调用线程将被阻塞,直到join()方法加入的join线程执行完毕为止。
static class JoinQueue implements Runnable {
private Thread thread;
public JoinQueue(Thread thread) {
this.thread = thread;
}
@Override
public void run() {
try {
thread.join();
System.out.println(Thread.currentThread().getName()+" terminted.");
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread previous = Thread.currentThread();
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new JoinQueue(previous), String.valueOf(i));
System.out.println(" thread " + previous.getName() + " is in front of " + thread.getName());
thread.start();
previous = thread;
}
Thread.sleep(2000);
System.out.println(Thread.currentThread()+" done");
}
4. 调用yield()、sleep()、wait()、notify()等对锁的影响
线程在执行yield()以后,持有的锁是不释放的;
sleep()方法被调用后,持有的锁是不释放的;
wait()方法调用前线程必须要持有的锁,调用wait()方法后,锁就会被释放,当wait()方法返回时候,线程会重新持有锁;
调用notify()方法之前,必须要持有锁,调用notify()方法本身不会释放锁的 。