Java并发编程的魅力之Join的用法
0x01 构造需求
现在假如我们有这样一个需求:
我们需要解析一个Excel 里多个Sheet 的数据,为了加快解析的速度,此时可以考虑使用多线程。
实现思路如下:
- 每个线程解析一个sheet 里面的数据。
- 等到所有的Sheet 都解析完成后,程序需要提示解析完成。
0x02 解决思路
2.1 菜鸟的错误写法
如果是一个新手菜鸟不懂Java 并发的话,可能会这么写:
/**
* @author qing-feng.zhao
* @功能
* @时间 2020/1/20 14:22
*/
public class JoinSampleTest{
public static void main(String[] args){
Thread thread1=new Thread(new Runnable(){
@Override
public void run(){
System.out.println("start to parse excel sheet one");
}
});
Thread thread2=new Thread(new Runnable(){
@Override
public void run(){
System.out.println("start to parse excel sheet two");
}
});
thread1.start();
thread2.start();
System.out.println("all parse finished");
}
}
这样写的结果你们猜会怎么样?
结果可能会输出这样:
all parse finished
start to parse excel sheet one
start to parse excel sheet two
当然由于线程执行先后顺序的不可确定性,还可能会输出这样的结果:
all parse finished
start to parse excel sheet two
start to parse excel sheet one
但是不管怎么样,这两种结果绝对都不是我们想要的。
我们其实希望的是线程一和线程二执行完成后,再输出 all parse finished 好不?
这还没干完活呢,就告诉领导干完活了,这样可不好吧?
2.2 懂并发编程的正确写法
那么到底应该怎么做才能达到我们想要的效果呢?
如果请教大神,大神可能会告诉你最简单的一种写法是使用join()
方法。
那么接下来就让我们试试join()
方法的神奇魅力。
/**
* @author qing-feng.zhao
* @功能
* @时间 2020/1/20 14:22
*/
public class JoinSampleTest{
public static void main(String[] args){
Thread thread1=new Thread(new Runnable(){
@Override
public void run(){
System.out.println("start to parse excel sheet one");
}
});
Thread thread2=new Thread(new Runnable(){
@Override
public void run(){
System.out.println("start to parse excel sheet two");
}
});
thread1.start();
thread2.start();
try {
thread1.join();
} catch (InterruptedException e) {
System.err.println("thread1 join error"+e);
}
try {
thread2.join();
} catch (InterruptedException e) {
System.err.println("thread2 join error"+e);
}
System.out.println("all parse finished");
}
}
执行后会输出如下结果:
start to parse excel sheet one
start to parse excel sheet two
all arse finished
诶,果然可以了哈。
0x03 join方法分析
join()
这么神奇,那么到底是怎么回事呢?
- 上面代码中我们关心的有三个线程,主线程,线程一,线程二
- 当然实际上不止三个线程,因为还有gc 垃圾回收等后台守护线程。
- 关于这个可以看我写的另外一篇博文,3. Java并发编程的魅力之线程的创建方法
- 我们希望线程一和线程二执行完成后,再输出一句话,所有线程都解析完了。
- join 的作用就是让当前执行线程等待join线程执行结束。
- 也就是说主线程中会等待thread1.join();和thread2.join() 方法执行完成后,才会执行最后一行的输出打印语句代码。
- 其实现原理是不停检查join线程是否存活,如果join线程存活则让当前线程永远等待。
- 其中,wait(0)表示永远等待下去,代码片段如下
while(isAlive()){ wait(0); }
- 直到join线程中止后,线程的
this.notifyAll()
方法会被调用- 调用
notifyAll()
方法是在JVM里实现的,所以在JDK里看不到,大家可以查看JVM源码。
本篇完~
更多精彩内容请关注博客专栏 Java并发编程的魅力 ,持续更新中。。。