定义
即 Guarded Suspension,用在一个线程等待另一个线程的执行结果
要点
- 有一个结果需要从一个线程传递到另一个线程,让他们关联同一个 GuardedObject
- 如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见生产者/消费者)
- JDK 中,join 的实现、Future 的实现,采用的就是此模式
- 因为要等待另一方的结果,因此归类到同步模式

join示例:
public static void main(String[] args){Thread t = new Thread(()->{Thread.sleep(1000);});t.join();System.out.println("1000");}
Future示例:
public static void main(String[] args) throws ExecutionException, InterruptedException {// 创建任务对象FutureTask<Integer> task3 = new FutureTask<>(() -> {System.out.println("hello");return 100;});// 主线程阻塞,同步等待 task 执行完毕的结果Integer result = task3.get();System.out.println("结果是:"+result);}
join()的原理
// 无参数的join,调用join(0)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");}// 无参的join方法会调用join(0),从而进入该分支if (millis == 0) {// 判断线程是否还存活,存活则调用wait等待while (isAlive()) {wait(0);}} else {// 判断线程是否还存活while (isAlive()) {// 计算剩余时间long delay = millis - now;// <=0 表示join等待已经超时,退出等待if (delay <= 0) {break;}// 使用带有时间的wait方法等待wait(delay);// 计算已过去的时间now = System.currentTimeMillis() - base;}}}// native方法,它会使线程进入等待,直到通过notify唤醒或者超时public final native void wait(long timeout) throws InterruptedException;public final native boolean isAlive();
通过阅读源码我们发现,如果我们调用无参数的join其实是调用了join(0),所以我们直接看有参数的join方法。
该方法分为两个分支,一个是millis=0,即无限时等待。另一个是millis>0,即限时等待。
/*** TestGuardedObject* <p>* join原理* </p>* encoding:UTF-8** @author lisonglin 23:36 2022/3/4*/public class TestGuardedObject {public static void main(String[] args) {GuardedObject v2 = new GuardedObject();new Thread(() -> {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}v2.complete(null);try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}v2.complete(Arrays.asList("a", "b", "c"));}).start();Object response = v2.get(2500);if (response != null) {System.out.println("get response: "+((List<String>) response).size()+"lines");} else {System.out.println("can't get response");}}}class GuardedObject {private Object response;private final Object lock = new Object();public Object get(){return get(0);}public Object get(long millis) {synchronized (lock) {long base = System.currentTimeMillis();long now = 0;if (millis == 0) {while (response == null) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}} else {while (response == null) {long delay = millis - now;System.out.println("waitTime:" + delay);if (delay <= 0) {System.out.println("break...");break;}try {lock.wait(delay);} catch (InterruptedException e) {e.printStackTrace();}now = System.currentTimeMillis() - base;System.out.println("timePassed:" + now + ", object is null");}}return response;}}public void complete(Object response) {synchronized (lock) {this.response = response;System.out.println("notify...");lock.notifyAll();}}}
waitTime:2500 notify... timePassed:1, object is null waitTime:2499 notify... timePassed:3, object is null get response: 3lines
