Java多线程控制台计算器:循环终止与数据丢失问题求解
控制台计算器多线程输入存储问题
问题现象
- 输入“=”时循环无法终止
- 部分输入数据丢失,未成功存入目标List
需求目标
实现多线程并行写入4个List,且用户输入“=”时立即终止循环
原代码核心问题
- 多Scanner抢占输入流:创建3个Scanner读取同一
System.in,会导致输入被重复读取、抢占,直接引发数据丢失和终止判断失效 - 终止逻辑完全错误:循环中先调用三次
scanner.nextLine(),强制要求输入三次内容才会判断是否等于“=”,违背“输入一次=就终止”的需求 - 输入重复消耗:循环先读取三次输入,线程启动后又再次调用
nextLine(),导致输入被重复消耗,数据无法正确存入List - 无效参数传递:线程方法的String参数是值传递,赋值后不影响外部变量,完全没必要作为参数传入
解决方案
核心调整点
- 只用一个Scanner读取输入,避免多实例抢占输入流
- 设立
volatile修饰的全局终止标志,保证多线程可见性 - 每个线程负责监听输入、写入对应List,同时检查终止条件
- 通过同步块或线程安全List保证写入操作的安全性
完整代码实现
1. 线程任务类
import java.util.List; import java.util.Scanner; public class ListWriterTask implements Runnable { private final List<String> targetList; private final Scanner scanner; private volatile boolean isTerminated; public ListWriterTask(List<String> targetList, Scanner scanner) { this.targetList = targetList; this.scanner = scanner; this.isTerminated = false; } public void terminate() { this.isTerminated = true; } @Override public void run() { while (!isTerminated) { // 保证同一时间只有一个线程读取输入 synchronized (scanner) { if (!scanner.hasNextLine()) { continue; } String input = scanner.nextLine().trim(); if ("=".equals(input)) { // 触发全局终止,volatile保证其他线程立即感知 terminate(); return; } // 保证List写入操作线程安全 synchronized (targetList) { targetList.add(input); } } // 短暂休眠,避免线程过度抢占CPU try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } } }
2. 测试主类
import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class CalculatorInputTest { public static void main(String[] args) throws InterruptedException { Scanner scanner = new Scanner(System.in); // 初始化4个目标List List<String> firstValues = new ArrayList<>(); List<String> symbols = new ArrayList<>(); List<String> secondValues = new ArrayList<>(); List<String> fourthValues = new ArrayList<>(); // 创建对应线程任务 ListWriterTask task1 = new ListWriterTask(firstValues, scanner); ListWriterTask task2 = new ListWriterTask(symbols, scanner); ListWriterTask task3 = new ListWriterTask(secondValues, scanner); ListWriterTask task4 = new ListWriterTask(fourthValues, scanner); // 启动线程 Thread thread1 = new Thread(task1); Thread thread2 = new Thread(task2); Thread thread3 = new Thread(task3); Thread thread4 = new Thread(task4); thread1.start(); thread2.start(); thread3.start(); thread4.start(); // 等待所有线程终止 thread1.join(); thread2.join(); thread3.join(); thread4.join(); // 输出所有List内容 System.out.println("第一个List: " + firstValues); System.out.println("符号List: " + symbols); System.out.println("第二个List: " + secondValues); System.out.println("第四个List: " + fourthValues); scanner.close(); } }
代码说明
- 单Scanner共享:所有线程共用一个Scanner,通过同步块保证输入读取的原子性,避免输入混乱
- volatile终止标志:
isTerminated用volatile修饰,确保一个线程触发终止后,其他线程能立即感知并停止运行 - 线程安全写入:通过同步块保护List的
add操作,也可直接替换为CopyOnWriteArrayList简化同步逻辑 - 性能优化:线程休眠100ms,避免无限制循环抢占CPU资源
内容的提问来源于stack exchange,提问作者Матвей Шавлов
相关产品推荐
相关产品推荐

