Java多线程Race condition下打印结果不符合预期问题咨询
问题现象
提供的Java多线程代码运行时,始终打印"Mares do eat oats.",无法输出开发者预期的"Mares do not eat oats."。开发者原本的逻辑预期是:主线程给静态变量message赋目标值后休眠2000ms,醒来就会打印该目标值。
注:原代码片段中
message = **"Mares do not eat oats.**";行的**是排版时误加的Markdown加粗标记,实际编译运行需要删除这两个符号,否则代码会报语法错误。
根因分析
问题出在多线程的执行时序和开发者的预期完全不符,和JVM内存可见性之类的底层机制无关,时间线非常明确:
- T0时刻:主线程调用
start()启动CorrectorThread子线程,子线程启动后第一时间执行sleep(1000),会在T0+1000ms的时间点醒来,执行修改message变量的逻辑。 - 主线程启动子线程后没有任何等待,立刻给静态变量
message赋值为"Mares do not eat oats.",随后执行sleep(2000),会在T0+2000ms的时间点醒来执行打印逻辑。 - T0+1000ms时刻:子线程比主线程早1000ms结束休眠,直接把全局共享的
message变量值覆盖为"Mares do eat oats.",执行完后子线程直接退出。 - T0+2000ms时刻:主线程休眠结束读取
message变量时,拿到的已经是被子线程覆盖过的值,自然打印不出预期内容。
另外要注意:靠Thread.sleep()控制多线程执行顺序本身就是非常不可靠的写法,不同机器的CPU负载、线程调度策略不同,休眠唤醒的时间点存在误差,很容易出现偶现的时序问题。
修复方案
根据实际业务需求选对应方案即可:
- 如果仅要满足当前打印预期:将
CorrectorThread中的休眠时长从1000ms调整为3000ms以上,保证子线程修改message的动作发生在主线程打印之后即可。 - 如果要稳定控制线程执行顺序:使用
Thread.join()、显式锁、CountDownLatch等线程同步工具明确约束执行顺序,不要依赖休眠时长判断时序。 - 如果子线程修改
message的逻辑本身是冗余的:直接删除子线程中给message赋值的语句即可。
参考可运行的修复代码:
public class BadThreads { static String message; private static class CorrectorThread extends Thread { public void run() { try { sleep(3000); } catch (InterruptedException e) { // 不要空吞中断异常,恢复中断标记是最佳实践 Thread.currentThread().interrupt(); } message = "Mares do eat oats."; } } public static void main(String args[]) throws InterruptedException { CorrectorThread correctorThread = new CorrectorThread(); correctorThread.start(); message = "Mares do not eat oats."; Thread.sleep(2000); System.out.println(message); // 等待子线程执行完成,避免程序直接退出 correctorThread.join(); } }
内容的提问来源于stack exchange,提问作者Vineel
相关产品推荐
相关产品推荐

