一 . 概述
join方法的核心作用就是:
当前线程等待子线程结束.
我们可以看到方法的重载,其实就是调用的线程等待子线程多少时间.
如果不传参数,默认为子线程完成之后才运行.
二 . 测试用例
public class JoinClass { public static void main(String[] args) { //创建一个线程,打印1到1000. Thread thread = new Thread() { @Override public void run() { print(); } }; //开启线程 thread.start();
// 加入子线程join ,那么主线程就会等待子线程完成任务.
thread.join(); //主线程也做同样的操作 print(); } public static void print() { for(int i = 0 ; i<1000;i++) System.out.println(Thread.currentThread().getName() + " running .... i="+i); } }
现在我们创建了一个任务,打印1到1000,主线程和一个子线程分别进行.
打印的效果就是主线程和子线程不断切换运行状态.
当我们在原先的代码加入一行.
看红色的部分,此时主线程就会等待子线程完成任务之后再去执行print()方法.
三 .分析
一旦加入了红色部分的代码之后,那么主线程就会阻塞自己,直到子线程完成自己的任务之后才会被唤醒.
因此,thread.join()方法一定要在print()方法之前,否则就不会在主线程开始任务就开始阻塞.
[理解 ]:
我们可以认为join()方法是一个将当前线程自我阻塞的方法,直到等待的线程完成之后才会运行.
四 . 永无止尽的循环
public class ForeverThread { public static void main(String[] args) throws Exception { // 主线程等待自己结束才会开始自己的任务... Thread.currentThread().join(); } }
上面的代码中,主线程一直在等待主线程自己运行结束.
而主线程一直又在等待自己运行结束.
那么就会出现一个循环.
等待
主线程--- ------> 主线程
等待
如上,主线程自己就能将自己锁定,一直都无法结束掉.
五 . 一个例子
public class TaskThread { public static void main(String[] args) throws Exception { long startTime = System.currentTimeMillis(); Thread t1 = new Thread(new Task("task1",1)); Thread t2 = new Thread(new Task("task2",2)); Thread t3 = new Thread(new Task("task3",3)); t1.start(); t2.start(); t3.start(); t1.join(); t2.join(); t3.join(); long endTime = System.currentTimeMillis(); System.out.println("main thread is done,spned time is = " + (endTime - startTime)); } } class Task implements Runnable{ //任务的名字 private final String taskName; //任务花费的时间 private final long costTime; public Task(String taskName ,long costTime) { this.taskName = taskName ; this.costTime = costTime; } public void run() { try { TimeUnit.SECONDS.sleep(costTime); System.out.println("任务 name = " + taskName + "完成了..."); } catch (InterruptedException e) { e.printStackTrace(); } } }
我们创建了一个线程任务类,其中需要传入一个任务的名字,一个线程需要花费的时间.
在主线程之中,我们创建了三个线程,分别启动之后,使用join.现在运行的结果为:
任务 name = task1完成了... 任务 name = task2完成了... 任务 name = task3完成了... main thread is done,spned time is = 3002
这个比较好理解: 主线程会在花费时间最长的线程结束之后终结自己.
下面我们调整一下代码的运行顺序:
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
现在是1线程首先运行,然后主线程等待1线程结束,然后再开启2线程,如此反复.
那么,这个方法实际上就相当于一个序列化的运行方式进行着,就是在排队.
通过这个例子:
我们知道join就是在阻塞自己,等待阻塞自己的任务结束之后才会运行自己.