如何按顺序执行Java线程?现有代码问题及替代方案咨询
问题分析与解决方案
首先纠正你代码里的两个核心问题:
flag变量未声明,必须添加volatile修饰的静态变量:private static volatile boolean flag = false;,否则连编译都通不过。- 原逻辑完全搞反了:打印"Second Function"的线程里写的是
while(flag),但初始flag是false,所以这个循环直接跳过,根本不会执行里面的打印和countDown操作,这才是导致countDownLatch.await()一直阻塞的真正原因,不是volatile的可见性问题。
如果你硬要让两个线程严格按First Function→Second Function的顺序执行,哪怕违背异步初衷,以下几种方法可行:
方法1:直接串行执行(最简单粗暴)
既然要顺序执行,干脆不搞异步启动,直接按顺序调用Runnable的run()方法,或者启动线程后调用join()等待前一个线程执行完:
修改executeAndWait方法:
public static void executeAndWait(List<Runnable> runnables) throws InterruptedException { for (Runnable r : runnables) { Thread t = new Thread(r); t.start(); t.join(); // 等待当前线程执行完再启动下一个 } }
注意要把runnables的顺序调整过来(原列表第一个是打印Second的,第二个是First的):
List<Runnable> runnables = Arrays.asList( () -> { try { Thread.sleep(100); System.out.println("First Function"); countDownLatch.countDown(); } catch(Exception e) {} }, () -> { try { Thread.sleep(100); System.out.println("Second Function"); countDownLatch.countDown(); } catch(Exception e) {} } );
这样启动后,第一个线程执行完First Function,第二个线程才会启动执行Second Function,完全符合顺序要求。
方法2:用CountDownLatch严格控制线程执行顺序
保留异步启动,但通过CountDownLatch让打印Second的线程等待打印First的线程执行完:
重新设计代码逻辑:
public class Application { // 用一个CountDownLatch控制Second线程等待First线程 private static CountDownLatch firstDoneLatch = new CountDownLatch(1); private static CountDownLatch allDoneLatch = new CountDownLatch(2); public static void executeAndWait(List<Runnable> runnables) { runnables.forEach(r -> new Thread(r).start()); } public static void main(String[] args) throws InterruptedException { List<Runnable> runnables = Arrays.asList( // 打印Second的线程:先等待First线程完成 () -> { try { firstDoneLatch.await(); // 等待First线程执行完 Thread.sleep(100); System.out.println("Second Function"); allDoneLatch.countDown(); } catch(Exception e) {} }, // 打印First的线程:执行完后通知Second线程 () -> { try { Thread.sleep(100); System.out.println("First Function"); firstDoneLatch.countDown(); // 通知Second线程可以执行了 allDoneLatch.countDown(); } catch(Exception e) {} } ); executeAndWait(runnables); allDoneLatch.await(); System.out.println("Main Execution Completed!"); } }
这里两个线程同时启动,但打印Second的线程会先阻塞在firstDoneLatch.await(),直到打印First的线程执行完并调用countDown(),才会继续执行,完美实现顺序要求。
方法3:使用Semaphore(信号量)控制
原理和CountDownLatch类似,用信号量让Second线程等待First线程释放许可:
public class Application { private static Semaphore semaphore = new Semaphore(0); private static CountDownLatch allDoneLatch = new CountDownLatch(2); public static void executeAndWait(List<Runnable> runnables) { runnables.forEach(r -> new Thread(r).start()); } public static void main(String[] args) throws InterruptedException { List<Runnable> runnables = Arrays.asList( () -> { try { semaphore.acquire(); // 等待许可 Thread.sleep(100); System.out.println("Second Function"); allDoneLatch.countDown(); } catch(Exception e) {} }, () -> { try { Thread.sleep(100); System.out.println("First Function"); semaphore.release(); // 释放许可给Second线程 allDoneLatch.countDown(); } catch(Exception e) {} } ); executeAndWait(runnables); allDoneLatch.await(); System.out.println("Main Execution Completed!"); } }
内容的提问来源于stack exchange,提问作者Curious Coder
相关产品推荐
相关产品推荐

