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

实现:
public class GuardedObject {//结果private Object response;//获取结果public Object get() throws InterruptedException {synchronized (this){//还没有结果while(response==null){this.wait();}}return response;}public void complete(Object response){synchronized (this){//给结果成员变量赋值this.response=response;this.notifyAll();}}}
GuardedObject类实现细节如上,一个成员变量用来存放存储结果,再自定义两个方法更改变量值。
具体实例:线程1等待线程2下载完毕内容,注意object相当于共享变量,所以类中方法要加入synchronized代码块。
import javax.imageio.IIOException;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;import java.nio.charset.StandardCharsets;import java.util.ArrayList;import java.util.List;public class GuardedObject {//结果private Object response;//获取结果public Object get() throws InterruptedException {synchronized (this){//还没有结果while(response==null){this.wait();}}return response;}public void complete(Object response){synchronized (this){//给结果成员变量赋值this.response=response;this.notifyAll();}}}class Test20{public static void main(String[] args) {GuardedObject object = new GuardedObject();new Thread(()->{//等待结果System.out.println("等待结果");List<String> list = null;try {list = (List<String>) object.get();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(list.size());},"t1").start();new Thread(()->{System.out.println("执行下载");List<String> list = null;try {list = Downloader.download();} catch (IOException e) {e.printStackTrace();}object.complete(list);},"t2").start();}}class Downloader{public static List<String> download() throws IOException{HttpURLConnection conn = (HttpURLConnection) new URL("www.baidu.com").openConnection();List<String> lines =new ArrayList<>();try(BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(),StandardCharsets.UTF_8))){String line;while ((line=reader.readLine())!=null){lines.add(line);}}return lines;}}
此种写法的好处,以往的join()方法,线程1需要用等待线程2完全执行结束才能拿到结果,但这是没必要的,完全可以在线程2生成结果后使得线程2继续执行。
所以这种带wait-notify的形式称为“保护性暂停”
扩展-增加超时:
当线程wait时候条件不得到满足,按照while-wait(空参)的写法,就会陷入空等,只有条件满足时线程才可以继续执行下去。所以要使用带参数的wait方法,控制等待的时间,如果时间满足则不再等待。
代码如下:
//获取结果public Object get(int timeout) throws InterruptedException {synchronized (this){long begin = System.currentTimeMillis();//定义经历的时间long passedTime = 0;while(response==null){long waitTime = timeout-passedTime;//经历的时间超过了最大等待时间,退出循环if(waitTime<=0){break;//跳出循环,不再等待}this.wait(waitTime);passedTime = System.currentTimeMillis()-begin;//获得经历时间}}return response;}
设置一个passedTime,记录循环中等待的时间,一旦超时则通过break跳出循环,线程执行。但是一定要注意虚假唤醒的情况,如果wait位置被notifyAll虚假唤醒,一定要将之前等待的时间扣除,是根据waitTime进一步判断,而不是根据timeout值判断,这里一定要注意。
