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

Java多线程控制台计算器:循环终止与数据丢失问题求解

控制台计算器多线程输入存储问题

问题现象

  • 输入“=”时循环无法终止
  • 部分输入数据丢失,未成功存入目标List

需求目标

实现多线程并行写入4个List,且用户输入“=”时立即终止循环


原代码核心问题

  1. 多Scanner抢占输入流:创建3个Scanner读取同一System.in,会导致输入被重复读取、抢占,直接引发数据丢失和终止判断失效
  2. 终止逻辑完全错误:循环中先调用三次scanner.nextLine(),强制要求输入三次内容才会判断是否等于“=”,违背“输入一次=就终止”的需求
  3. 输入重复消耗:循环先读取三次输入,线程启动后又再次调用nextLine(),导致输入被重复消耗,数据无法正确存入List
  4. 无效参数传递:线程方法的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,提问作者Матвей Шавлов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:27:05