Java中线程通信协作的最常见的两种方式:
一.syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()
二.ReentrantLock类加锁的线程的Condition类的await()/signal()/signalAll()
Java是通过Object类的wait()、notify()、notifyAll()这几个方法来实现线程间通信的。
- wait():告诉当前线程放弃监视器并进入睡眠状态,直到其他线程进入同一监视器并调用notify()为止。
- notify():唤醒同一对象监视器中调用wait()的第一个线程。这类似排队买票,一个人买完之后,才能让后面的人买。
- notifyAll():醒同一对象监视器中调用wait()的所有线程,具有最高优先级的线程首先被唤醒并执行。
wait()、notify()、notifyAll()这三个方法只能在synchronized方法中调用,即无论线程调用一个对象的wait还是notify方法,该线程必须先得到该对象的锁标记。这样notify就只能唤醒同一对象监视器中调用wait的线程。而使用多个对象监视器,就可以分别有多个wait、notify的情况,同组理的wait只能被同组的notify唤醒。

join()
在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。
对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先于 b 线程的输出。
public class JoinExample {private class A extends Thread {@Overridepublic void run() {System.out.println("A");}}private class B extends Thread {private A a;B(A a) {this.a = a;}@Overridepublic void run() {try {a.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("B");}}public void test() {A a = new A();B b = new B(a);b.start();a.start();}}public static void main(String[] args) {JoinExample example = new JoinExample();example.test();}/*AB*/
wait() notify() notifyAll()
调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。
它们都属于 Object 的一部分,而不属于 Thread。
只能用在同步方法或者同步控制块中使用,否则会在运行时抛出 IllegalMonitorStateException。
使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁。
public class WaitNotifyExample {public synchronized void before() {System.out.println("before");notifyAll();}public synchronized void after() {try {wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("after");}}public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();WaitNotifyExample example = new WaitNotifyExample();executorService.execute(() -> example.after());executorService.execute(() -> example.before());}/*beforeafter*/
await() signal() signalAll()
java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调,可以在 Condition 上调用 await() 方法使线程等待,其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程。
相比于 wait() 这种等待方式,await() 可以指定等待的条件,因此更加灵活。
使用 Lock 来获取一个 Condition 对象。
public class AwaitSignalExample {private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();public void before() {lock.lock();try {System.out.println("before");condition.signalAll();} finally {lock.unlock();}}public void after() {lock.lock();try {condition.await();System.out.println("after");} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();AwaitSignalExample example = new AwaitSignalExample();executorService.execute(() -> example.after());executorService.execute(() -> example.before());}/*beforeafter*/
