Java双线程生成有序奇偶数字:输出无序且不完整问题
问题分析与修复方案
核心问题
- 主线程提前打印列表:主线程启动工作线程后立刻输出列表,此时线程尚未执行完毕,导致输出不完整甚至为空。
- 同步逻辑缺陷:
- 奇数线程添加元素后进入等待,但偶数线程循环结束后未触发最后一次通知,会导致奇数线程永久阻塞。
- 现有逻辑无法保证严格的数字顺序,比如奇数线程先启动会先添加1,再等待偶数线程添加0,造成顺序混乱。
修复后的完整代码
import java.util.ArrayList; import java.util.List; import java.util.Scanner; class Odd implements Runnable { private final int number; private final List<Integer> allNumber; public Odd(int number, List<Integer> allNumber) { this.number = number; this.allNumber = allNumber; } @Override public void run() { synchronized (allNumber) { for (int i = 1; i <= number; i += 2) { // 等待偶数线程完成前一次添加,保证顺序 while (allNumber.size() % 2 != 0) { try { allNumber.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } allNumber.add(i); allNumber.notify(); } } } } class Even implements Runnable { private final int number; private final List<Integer> allNumber; public Even(int number, List<Integer> allNumber) { this.number = number; this.allNumber = allNumber; } @Override public void run() { synchronized (allNumber) { for (int i = 0; i <= number; i += 2) { // 等待奇数线程完成前一次添加,保证顺序 while (allNumber.size() % 2 == 0 && !allNumber.isEmpty()) { try { allNumber.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } allNumber.add(i); allNumber.notify(); } // 最后一次通知,防止奇数线程阻塞 allNumber.notify(); } } } public class Main { private static Scanner input = new Scanner(System.in); public static void main(String[] args) throws InterruptedException { System.out.print("Enter Your Number: "); int number = input.nextInt(); List<Integer> sharedList = new ArrayList<>(); Odd oddThread = new Odd(number, sharedList); Even evenThread = new Even(number, sharedList); Thread thread = new Thread(oddThread); Thread thread1 = new Thread(evenThread); thread.start(); thread1.start(); // 等待两个线程执行完毕再打印 thread.join(); thread1.join(); System.out.println("List: " + sharedList); } }
关键修复说明
- 主线程等待线程完成:通过
join()方法让主线程等待工作线程执行完毕,确保列表数据完整后再输出。 - 基于列表大小的顺序控制:通过判断列表长度的奇偶性,强制偶数、奇数线程交替添加元素,保证数字按0,1,2,3...的顺序排列。
- 循环等待避免虚假唤醒:使用
while循环判断等待条件,防止线程被虚假唤醒后错误执行添加操作。 - 收尾通知:偶数线程循环结束后额外调用一次
notify(),确保奇数线程不会因最后一次等待而永久阻塞。
内容的提问来源于stack exchange,提问作者xaso
相关产品推荐
相关产品推荐

