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

Java多线程模拟跑步比赛 如何实现选手排名及总耗时统计

问题原因

  • 总耗时统计错误:主线程调用start()启动子线程后不会阻塞等待子线程执行完成,会直接执行后续计算总耗时的逻辑,拿到的时间仅为启动线程的耗时,和实际比赛时长不符。
  • 排名无法正确分配:多线程并发执行时,普通int变量的更新不是原子操作,存在线程安全问题,无法保证先跑完的线程优先拿到递增的排名。

解决方案

步骤1:修改Runner类,添加线程安全的排名计数器

使用AtomicInteger作为全局共享的排名计数器,保证排名分配的原子性,避免并发冲突:

import java.util.concurrent.atomic.AtomicInteger;

public class Runner extends Thread {
    // 全局共享的原子排名计数器,初始值为1
    private static final AtomicInteger rankCounter = new AtomicInteger(1);
    // 原有成员变量:lane、bib、country、lastName、firstName、reaction等保持不变

    // 修改后的raceStart方法
    private void raceStart() throws InterruptedException {
        long start = System.currentTimeMillis();
        Thread.sleep((long) (reaction * 1000));
        int track = 100;
        int playerLocation = 0;
        Random randomDelay = new Random();
        double delay = 90 + randomDelay.nextInt(16);
        for(int i = 0; i <= track; i++) {
            if(playerLocation == track) {
                long finish = System.currentTimeMillis();
                double totalTime = (double)(finish - start) / 1000;
                // 原子获取当前排名,计数器自动+1
                int currentRank = rankCounter.getAndIncrement();
                System.out.format("%d %d %d %-12s %-12s %-25s %.3f %.3f%n" , currentRank, lane, bib, country, lastName, firstName, reaction, totalTime);
            }
            playerLocation++;
            Thread.sleep((long) delay);
        }
    }

    // 原有构造方法等逻辑保持不变
}

步骤2:修改主类逻辑,等待所有线程执行完成后统计总耗时

启动所有选手线程后,调用join()方法阻塞主线程,直到所有选手线程执行完毕再计算总耗时:

// 修改后的run方法,返回所有选手线程实例
private List<Runner> run() {
    Runner usainBolt = new Runner(1, 6, 2612, "JAM", "Bolt", "Usain", 0.155);
    Runner justinGatlin = new Runner(2, 4, 3069, "USA", "GATLIN", "Justin", 0.152);
    Runner andreDeGrasse = new Runner(3, 7, 2196, "CAN", "DE GRASSE", "Andre", 0.141);
    Runner yohanBlake = new Runner(4, 9, 2611, "JAM", "BLAKE", "Yohan", 0.145);
    Runner akaniSimbine = new Runner(5, 3, 2909, "RSA", "SIMBINE", "Akani", 0.128);
    Runner benYoussefMeite = new Runner(6, 8, 2245, "CIV", "MEITE", "Ben Youssef", 0.156);
    Runner jimmyVicaut = new Runner(7, 5, 2434, "FRA", "VICAUT", "Jimmy", 0.140);
    Runner trayvonBromell = new Runner(8, 2, 3054, "USA", "BROMWELL", "Trayvon", 0.135);

    List<Runner> runners = Arrays.asList(usainBolt, justinGatlin, andreDeGrasse, 
            yohanBlake, akaniSimbine, benYoussefMeite, jimmyVicaut, trayvonBromell);

    for (Runner r : runners) {
        r.start();
    }
    return runners;
}

// 总耗时统计逻辑
public static void main(String[] args) throws InterruptedException {
    long start = System.currentTimeMillis();
    List<Runner> runners = new MainClass().run();
    // 等待所有选手线程执行完成
    for (Runner r : runners) {
        r.join();
    }
    long finish = System.currentTimeMillis();
    double totalTime = (double)(finish - start) / 1000;
    System.out.println("比赛总耗时:" + totalTime + "秒");
}

可选优化

如果要避免线程启动顺序带来的时间误差,让所有选手完全同时起跑,可以使用CountDownLatch作为起跑信号,所有选手线程等待主线程统一发令后再开始执行。

内容的提问来源于stack exchange,提问作者Dalvir Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 18:57:03