You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java多线程赛跑程序移除System.out.println后逻辑异常排查

问题根因

你的代码存在4个核心并发错误,删掉System.out.println后逻辑错乱只是刚好戳破了之前的假正常现象:

  • 锁完全不生效:ThreadThings里的lock是实例变量,每个选手线程都持有自己独立的锁对象,加锁操作只锁当前线程自己,根本没法和其他线程形成互斥。Main方法里定义的锁和子线程任务完全无关,主线程加锁解锁对子线程执行没有任何影响,属于无效代码。
  • 共享变量无可见性保证:静态标记winner是所有线程共享的状态,但你既没有用volatile修饰,也没有在有效锁的保护下读写,一个线程修改winner=true之后,其他线程可能一直从自己的工作缓存里读到旧的false值。之所以留着println的时候看起来正常,是因为System.out.println底层实现自带synchronized同步,调用时会触发内存屏障强制刷新线程缓存,歪打正着保证了变量可见性,删掉之后这个偶然的保障消失,并发问题直接暴露。
  • 锁的粒度完全错误:你把整段跑步逻辑都包在锁里,就算锁是有效的,也会变成一个线程拿锁之后直接跑完100米全程才释放锁,其他线程全程等着,完全是串行执行,根本不是多线程赛跑的效果。
  • 无效的同步修饰:你给run方法加的synchronized关键字锁的是当前ThreadThings实例,和你定义的实例锁一样,没法跨实例同步多个线程,没有任何实际作用。
修正实现

修正逻辑遵循三个原则:所有线程共用同一把锁、只在判断/更新冠军状态的临界区加锁、锁释放必须放在finally块避免死锁,同时给共享状态加可见性保证。
修正后的ThreadThings类:

package com.company;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadThings implements Runnable {
    // 全局共享锁,所有参赛线程共用
    private static final Lock RACE_LOCK = new ReentrantLock();
    // 全局冠军标记,volatile保证多线程间的修改可见
    private static volatile boolean hasWinner = false;

    private final String runnerName;
    private int position = 0;

    public ThreadThings(String runnerName) {
        this.runnerName = runnerName;
    }

    @Override
    public void run() {
        long startTime = System.currentTimeMillis();
        for (int i = 1; i <= 100; i++) {
            position = i;
            // 模拟跑步耗时,可替换为随机休眠模拟真实速度差异
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }

            // 冲线时进入临界区判定冠军
            if (position == 100) {
                RACE_LOCK.lock();
                try {
                    if (!hasWinner) {
                        hasWinner = true;
                        System.out.println(runnerName + " wins");
                        System.out.println("Congrats " + runnerName + " you are the winner");
                    }
                } finally {
                    RACE_LOCK.unlock();
                }
            }
        }
        long totalTime = System.currentTimeMillis() - startTime;
        System.out.println(runnerName + " finished, total time: " + totalTime + "ms");
    }
}

修正后的Main类,删掉无效的锁逻辑:

package com.company;

public class Main {
    public static void main(String[] args) {
        new Thread(new ThreadThings("Abby")).start();
        new Thread(new ThreadThings("Brandon")).start();
        new Thread(new ThreadThings("Casey")).start();
        new Thread(new ThreadThings("David")).start();
        new Thread(new ThreadThings("Eddie")).start();
        new Thread(new ThreadThings("Frank")).start();
        new Thread(new ThreadThings("Gabby")).start();
        new Thread(new ThreadThings("Hannah")).start();
        new Thread(new ThreadThings("Indie")).start();
        new Thread(new ThreadThings("Jasmine")).start();
    }
}

补充说明:原代码里的耗时单位标注错误,System.currentTimeMillis()返回的时间戳单位是毫秒,不是分钟。如果要模拟更真实的赛跑效果,可以把固定10ms的休眠替换为Thread.sleep((long)(Math.random() * 20)),让每个选手的每米耗时随机。

内容的提问来源于stack exchange,提问作者Rhion Kendall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 22:24:12