如何控制两个线程run方法的执行顺序?为何输出中running...不连续?
问题1:如何控制两个线程run方法的执行顺序?
默认情况下,Java线程采用抢占式调度,CPU会随机给就绪状态的线程分配时间片,所以线程执行顺序是不确定的。如果要严格控制两个线程run()方法的执行顺序,有几种实用方案:
使用
join()方法:这是最直接的同步方式,让一个线程等待另一个线程执行完毕后再继续运行。比如在你的代码里,想让t1的run()先执行完再启动t2的run(),可以修改主线程逻辑:t1.start(); t1.join(); // 主线程暂停,等待t1执行完成 t2.start();这样
t2会在t1彻底执行结束后,才启动并执行自己的run()方法。使用
CountDownLatch同步工具:适合更复杂的多线程同步场景。比如初始化一个计数为1的CountDownLatch,让t2在run()方法里等待这个latch,t1执行完后调用countDown(),t2就会立刻开始执行。使用单线程线程池:通过
Executors.newSingleThreadExecutor()创建单线程池,把两个线程任务提交进去,线程池会严格按照提交顺序依次执行任务,自然就能控制顺序。
问题2:最后一个"running..."为何没有紧跟在第一个"running..."之后输出?
这是线程并发调度特性导致的正常现象,我们拆解下代码的执行流程就懂了:
- 主线程先创建
t1、t2对象,打印它们的初始名称和t1的ID。 - 调用
t1.start()和t2.start():这两个方法只是把线程从新建状态转为就绪状态,等着CPU分配时间片,并不是立刻执行run()方法。 - 主线程不会等子线程,会继续执行后续代码:修改
t1的名称,打印After changing name of t1:Sonoo Jaiswal。 - CPU会在主线程和两个就绪的子线程之间随机分配时间片:可能主线程先跑完自己的打印逻辑,才轮到
t2执行run();也可能子线程的执行被主线程打断,输出穿插在一起。
你看到的输出顺序就是典型的并发执行结果,因为没有任何同步机制保证两个子线程的run()会连续执行。比如实际执行时序可能是这样的:
主线程:打印t1/t2名称 → 打印t1的ID → 启动t1 → 启动t2 → 修改t1名称 → 打印修改后的名称
子线程t1:被CPU调度 → 打印"running..."
子线程t2:主线程完成打印后才被CPU调度 → 打印"running..."
这就导致两个"running..."之间插入了主线程的输出内容。
内容的提问来源于stack exchange,提问作者Math_Zombie

