执行逻辑:在当前代码块(比如main方法)中的线程A执行了join方法,
那么当代码块(main)执行到join方法时,会停止继续向下执行,一直到线程A执行完毕,
main方法才会继续向下执行。
代码一:
package com.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream; public class ThreadJoin { public static void main(String[] args) throws InterruptedException { Thread thread1=new Thread(new Runnable() { @Override public void run() { for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } },"线程1"); Thread thread2=new Thread(new Runnable() { @Override public void run() { for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } },"线程2"); //启动线程1 thread1.start(); //启动线程2 thread2.start(); /** * 当代码执行到这一步的时候,程序不再向下执行,等待thread1执行完毕后向下执行 * 同时thread1和thread2相互挣多cpu调度资源 */ thread1.join(); /** * 当代码执行到这一步的时候,程序不在向下执行,等待thread2执行完毕后向下执行 * 因为此时的thread1已经执行完毕了,只用thread2执行 */ thread2.join(); for(int i=0;i<2;i++){ System.out.println(Thread.currentThread().getName()+"#"+i); TimeUnit.SECONDS.sleep(1); } } }
使用案例:
假如现在有一个长途车票销售网站,想要查询合肥到上海的汽车;
而合肥又有很多的汽车站(合肥1站,合肥2站,合肥3站),同时上海也有很多的汽车站(上海1站,上海2站,上海3站)。
这个时候网站平台需要调用合肥的各个汽车平台官方的接口来获取合肥到上海的车票信息。
正常的同步思维应该是这样子的:
1.先调用合肥1站到上海站的车票信息,耗时3s,
2.调用合肥2站到上海站的车票信息,耗时5s,
3.调用合肥3站到上海站的车票信息,耗时1s。
等这3个接口调用完毕后,组装返回的参数展示到界面。
有了线程的join方法就可以同时让这三个接口去请求接口,等三个接口调用完毕后再组装参数展示给客户。
这是总耗时取决于返回接口数据最慢的那一个接口。
Platform.java 车站类
package com.thread.car; import java.util.ArrayList; import java.util.List; /** * 合肥车站1 */ public class PlatForm { private String startCity; private String endCity; public PlatForm(String startCity,String endCity) { this.startCity=startCity; this.endCity=endCity; } private final List<String> list=new ArrayList<>(); public void search(){ this.list.add(this.startCity+"站到"+this.endCity+"1站的信息"); this.list.add(this.startCity+"站到"+this.endCity+"2站的信息"); this.list.add(this.startCity+"站到"+this.endCity+"3站的信息"); } public List<String> get(){ return this.list; } }
Test.java 测试类
package com.thread.car; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; public class Test { /*private static List<String> resList=new ArrayList<>(); private static synchronized void addList(List<String> list){ resList.addAll(list); }*/ public static void main(String[] args) throws InterruptedException { //List<String> list=new ArrayList<String>(); PlatForm pf1=new PlatForm("合肥1","上海"); PlatForm pf2=new PlatForm("合肥2","上海"); PlatForm pf3=new PlatForm("合肥3","上海"); Thread thread1=new Thread(new Runnable() { @Override public void run() { try { pf1.search(); TimeUnit.SECONDS.sleep(5); System.out.println(Thread.currentThread().getName()+"执行结束"); } catch (InterruptedException e) { e.printStackTrace(); } } },"合肥1站"); Thread thread2=new Thread(new Runnable() { @Override public void run() { try { pf2.search(); TimeUnit.SECONDS.sleep(4); System.out.println(Thread.currentThread().getName()+"执行结束"); } catch (InterruptedException e) { e.printStackTrace(); } } },"合肥2站"); Thread thread3=new Thread(new Runnable() { @Override public void run() { try { pf3.search(); TimeUnit.SECONDS.sleep(1); System.out.println(Thread.currentThread().getName()+"执行结束"); } catch (InterruptedException e) { e.printStackTrace(); } } },"合肥3站"); thread1.start(); thread2.start(); thread3.start(); long start=System.currentTimeMillis(); thread1.join(); thread2.join(); thread3.join(); long end=System.currentTimeMillis(); System.out.println((end-start)/1000); List<String> list=new ArrayList<String>(); list.addAll(pf1.get()); list.addAll(pf2.get()); list.addAll(pf3.get()); for(String s:list){ System.out.println(s); } } }