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

添加Runnable多线程后排序输出首元素重复的代码修改问询

问题分析与解决方案

首先咱们来揪出这个重复元素问题的核心根源:你的主线程在启动排序线程后,根本没等排序线程完成就直接打印列表了!

你看main方法里的代码逻辑:启动name线程后立刻就开始遍历list1输出内容,但nameOrder方法里每次循环都加了Thread.sleep(100),排序过程会变得非常慢。这就导致两个线程同时操作同一个ArrayList——排序线程在一边修改列表元素,主线程在一边读取打印,而ArrayList本身是非线程安全的集合,这种并发读写的场景下,必然会出现数据错乱(也就是你看到的首个元素重复的情况)。

具体问题点拆解

  • 线程同步缺失:主线程和排序线程没有同步机制,主线程提前执行打印操作,拿到的是未完成排序且被并发修改的列表状态
  • 非线程安全集合:ArrayList不支持并发的读写/修改操作,多线程下会出现不可预期的行为
  • 排序延迟放大问题:Thread.sleep(100)让排序过程变慢,进一步放大了并发问题的出现概率

修复方案

方案1:让主线程等待排序线程完成(最直接有效)

在启动排序线程后,调用join()方法,让主线程阻塞直到排序线程执行完毕,再执行打印操作:

name.start();
try {
    name.join(); // 强制主线程等待排序线程执行完成
} catch (InterruptedException e) {
    e.printStackTrace();
}
// 现在打印的就是完全排序后的结果
for (Student i : list1) {
    System.out.println(i.toString());
}

方案2:改用线程安全集合(可选,需配合同步)

如果确实需要多线程同时操作集合,可以把ArrayList换成线程安全的CopyOnWriteArrayList,不过这个集合更适合读多写少的场景,排序这种频繁修改的场景性能会稍差,但能避免并发修改的异常:

List<Student> list1 = new CopyOnWriteArrayList<Student>();

不过即使换了线程安全集合,还是建议加上join(),否则你打印的可能还是未完成排序的中间状态列表。

额外优化建议

  • 如果排序不需要异步执行,其实没必要把排序放到线程里,单线程执行就不会有这些问题
  • 你自己实现的冒泡排序可以替换成JDK自带的高效排序方法,配合自定义比较器,既简洁又避免手写排序的bug:
Collections.sort(list1, (s1, s2) -> {
    int nameCompare = s1.getName().compareToIgnoreCase(s2.getName());
    if (nameCompare != 0) {
        return nameCompare;
    }
    // 名称相同时按pointValue降序排列
    return Double.compare(s2.pointValue(), s1.pointValue());
});

内容的提问来源于stack exchange,提问作者Samuel Rodriguez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:56:12