注意:线程的执行顺序与你想象的可能不一样!
大家好,我是冰河~~
今天,我们一起来讲讲线程的执行顺序,可能与你想象的不一样,全程高能,一起加油~~
一、线程的执行顺序是不确定的
调用 Thread 的 start()方法启动线程时,线程的执行顺序是不确定的。也就是说,在同一个方法中,连续创建多个线程后,调用线程的 start()方法的顺序并不能决定线程的执行顺序。
例如,这里,看一个简单的示例程序,如下所示。
在 ThreadSort01 类中分别创建了三个不同的线程,thread1、thread2 和 thread3,接下来,在程序中按照顺序分别调用 thread1.start()、thread2.start()和 thread3.start()方法来分别启动三个不同的线程。
那么,问题来了,线程的执行顺序是否按照 thread1、thread2 和 thread3 的顺序执行呢?运行 ThreadSort01 的 main 方法,结果如下所示。
再次运行时,结果如下所示。
第三次运行时,结果如下所示。
可以看到,每次运行程序时,线程的执行顺序可能不同。线程的启动顺序并不能决定线程的执行顺序。
二、如何确保线程的执行顺序
1.确保线程执行顺序的简单示例
在实际业务场景中,有时,后启动的线程可能需要依赖先启动的线程执行完成才能正确的执行线程中的业务逻辑。此时,就需要确保线程的执行顺序。那么如何确保线程的执行顺序呢?
可以使用 Thread 类中的 join()方法来确保线程的执行顺序。例如,下面的测试代码。
可以看到,ThreadSort02 类比 ThreadSort01 类,在每个线程的启动方法下面添加了调用线程的 join()方法。此时,运行 ThreadSort02 类,结果如下所示。
再次运行时,结果如下所示。
第三次运行时,结果如下所示。
可以看到,每次运行的结果都是相同的,所以,使用 Thread 的 join()方法能够保证线程的先后执行顺序。
2.join 方法如何确保线程的执行顺序
既然 Thread 类的 join()方法能够确保线程的执行顺序,我们就一起来看看 Thread 类的 join()方法到底是个什么鬼。
进入 Thread 的 join()方法,如下所示。
可以看到 join()方法调用同类中的一个有参 join()方法,并传递参数 0。继续跟进代码,如下所示。
可以看到,有一个 long 类型参数的 join()方法使用了 synchroinzed 修饰,说明这个方法同一时刻只能被一个实例或者方法调用。由于,传递的参数为 0,所以,程序会进入如下代码逻辑。
首先,在代码中以 while 循环的方式来判断当前线程是否已经启动处于活跃状态,如果已经启动处于活跃状态,则调用同类中的 wait()方法,并传递参数 0。继续跟进 wait()方法,如下所示。
可以看到,wait()方法是一个本地方法,通过 JNI 的方式调用 JDK 底层的方法来使线程等待执行完成。
需要注意的是,调用线程的 wait()方法时,会使主线程处于等待状态,等待子线程执行完成后再次向下执行。也就是说,在 ThreadSort02 类的 main()方法中,调用子线程的 join()方法,会阻塞 main()方法的执行,当子线程执行完成后,main()方法会继续向下执行,启动第二个子线程,并执行子线程的业务逻辑,以此类推。
好了,今天就到这儿吧,我是冰河,我们下期见~~
版权声明: 本文为 InfoQ 作者【冰河】的原创文章。
原文链接:【http://xie.infoq.cn/article/f101f9cc242cd16992293a3f6】。文章转载请联系作者。
评论