本节对 join 方法进行深入的剖析,主要内容点如下:
方法定义:多线程环境下,如果需要确保某一线程执行完毕后才可继续执行后续的代码,就可以通过使用 join 方法完成这一需求设计。
在项目实践中经常会遇到一个场景,就是需要等待某几件事情完成后主线程才能继续往下执行, 比如多个线程加载资源, 需要等待多个线程全部加载完毕再汇总处理。
Thread 类中有一个 join 方法就可以做这个事情,join 方法是 Thread 类直接提供的。join 是无参且返回值为 void 的方法。
如上图所示,假如有 3 个线程执行逻辑,线程 1 需要执行5秒钟,线程 2 需要执行10 秒钟,线程 3 需要执行 8 秒钟。 如果我们的开发需求是:必须等 3 条线程都完成执行之后再进行后续的代码处理,这时候我们就需要使用到 join 方法。
使用 join 方法后:
这就是 join 方法的作用与解释。
join 方法是 Thread 类中的方法,为了了解该方法的异常处理,我们先来简要的看下 join 方法的 JDK 源码:
public final void join() throws InterruptedException {
join(0);
}
从源代码中我们可以看到, join 方法抛出了异常:
throws InterruptedException
所以,我们在使用 join 方法的时候,需要对 join 方法的调用进行 try catch 处理或者从方法级别进行异常的抛出。
try-catch 处理示例:
public class DemoTest implements Runnable{
@Override
public void run() {
System.out.println("线程:"+Thread.currentThread()+" 正在执行...");
}
public static void main(String[] args) {
Thread t1 = new Thread(new DemoTest());
t1. start();
try {
t1.join();
} catch (InterruptedException e) {
// 异常捕捉处理
}
}
}
throws 异常处理示例:
public class DemoTest implements Runnable throws InterruptedException {
@Override
public void run() {...}
public static void main(String[] args) {
Thread t1 = new Thread(new DemoTest());
t1. start();
t1.join();
}
}
为了更好的了解 join 方法的使用,我们首先来设计一个使用的场景。
场景设计:
需求:我们需要等 3 个线程都执行完毕后,再进行后续代码的执行。3 个线程执行完毕后,请打印执行时间。
期望结果: 10 秒执行时间。
看到这个是不是似曾相识呢? 这就是我们本节第 2 知识点所举出的示例,现在我们来进行代码实现和验证,体会 join 方法的使用。
实例:
public class DemoTest{
public static void main(String[] args) throws InterruptedException {
Thread threadOne = new Thread(new Runnable() { //线程 1
@Override
public void run() {
try {
Thread.sleep (5000 ); //线程 1 休眠 5 秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println ("线程 1 休眠 5 秒钟,执行完毕。");
}
});
Thread threadTwo = new Thread(new Runnable() { //线程 2
...
Thread.sleep (10000 ); //线程 2 修眠 10 秒钟
...
System.out.println ("线程 2 修眠 10 秒钟,执行完毕。");
}
});
Thread threadThree = new Thread(new Runnable() {//线程 3
...
Thread.sleep (8000 ); //线程 3 修眠 8 秒钟
...
System.out.println ("线程 3 修眠 8 秒钟,执行完毕。");
}
});
Long startTime = System.currentTimeMillis();
threadOne. start();threadTwo. start();threadThree. start();
System.out.println("等待三个线程全部执行完毕再继续向下执行,我要使用 join 方法了。");
threadOne.join(); //线程 1 调用 join 方法
threadTwo.join(); //线程 2 调用 join 方法
threadThree.join(); //线程 3 调用 join 方法
Long endTime = System.currentTimeMillis();
System.out.println("三个线程都执行完毕了,共用时: "+ (endTime - startTime) + "毫秒");
}
}
执行结果验证:
等待三个线程全部执行完毕再继续向下执行,我要使用 join 方法了。
线程 1 休眠 5 秒钟,执行完毕。
线程 3 修眠 8 秒钟,执行完毕。
线程 2 修眠 10 秒钟,执行完毕。
三个线程都执行完毕了,共用时: 10002毫秒
从执行的结果来看,与我们对 join 方法的理解和分析完全相符,请同学也进行代码的编写和运行,加深学习印象。
除了无参的 join 方法以外, Thread 类还提供了有参 join 方法如下:
public final synchronized void join(long millis)
throws InterruptedException
该方法的参数 long millis 代表的是毫秒时间。
方法作用描述:等待 millis 毫秒终止线程,假如这段时间内该线程还没执行完,也不会再继续等待。
结合上一个知识点的代码,我们都是调用的无参 join 方法,现在对上一个知识点代码进行如下调整:
threadOne.join(); //线程 1 调用 join 方法
threadTwo.join(3000); //线程 2 调用 join 方法
threadThree.join(); //线程 3 调用 join 方法
从代码中我们看到,线程 2 使用 join 方法 3000 毫秒的等待时间,如果 3000 毫毛后,线程 2 还未执行完毕,那么主线程则放弃等待线程 2,只关心线程 1 和线程 3。
我们来看下执行结果:
等待三个线程全部执行完毕再继续向下执行,我要使用 join 方法了。
线程 1 休眠 5 秒钟,执行完毕。
线程 3 修眠 8 秒钟,执行完毕。
三个线程都执行完毕了,共用时: 8000毫秒
线程 2 修眠 10 秒钟,执行完毕。
从执行结果来看, 总用时 8000 毫秒,因为线程 2 被放弃等待了,所以只考虑线程 1 和线程 3 的执行时间即可。
在实际的开发场景中,经常会设计到对 join 方法的使用,无参方法使用更加常见,了解 join 方法的使用非常重要。
本节重中之重,就是掌握 join 方法的使用,join 方法在后续的开发工作中非常关键,很多情况下都会有所使用。
0/1000