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

Java中Scanner与Thread实现并行字符串识别失效问题求助

问题解决:同时支持控制台与JOptionPane并行输入,输入后自动关闭另一个输入源

核心问题分析

你的代码存在三个关键错误,导致并行逻辑失效:

  1. 线程未真正启动:调用Thread.run()只是在当前线程执行代码,没有创建新线程。必须用Thread.start()才能启动并行线程。
  2. Swing线程安全问题:Swing组件(包括JOptionPane)必须在**事件调度线程(EDT)**中创建和操作,直接在自定义线程中调用会引发线程安全问题,导致UI显示异常。
  3. 缺乏输入互斥终止逻辑:没有实现"一个输入完成后立即关闭另一个输入源"的逻辑,导致两个输入源互相干扰。

修正后的实现代码

以下是完整的可运行解决方案,实现了控制台与弹窗并行输入,任意一个输入完成后自动关闭另一个输入源:

import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class DualInputHandler {
    private volatile String inputResult = null;
    private final CountDownLatch latch = new CountDownLatch(1);
    private JOptionPane currentOptionPane;

    // 启动控制台输入线程
    private void startConsoleInput() {
        new Thread(() -> {
            try (Scanner sc = new Scanner(System.in)) {
                System.out.println("请在控制台输入或在弹窗中选择:");
                String consoleInput = sc.nextLine().trim();
                if (!consoleInput.isEmpty()) {
                    inputResult = consoleInput;
                    latch.countDown();
                    // 关闭弹窗
                    closeOptionPane();
                }
            }
        }).start();
    }

    // 启动弹窗输入(必须在EDT线程执行)
    private void startOptionPaneInput() {
        SwingUtilities.invokeLater(() -> {
            currentOptionPane = new JOptionPane(
                    "请选择参考项:",
                    JOptionPane.PLAIN_MESSAGE,
                    JOptionPane.OK_CANCEL_OPTION,
                    null,
                    null,
                    ""
            );
            JDialog dialog = currentOptionPane.createDialog("选择名称");
            dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            dialog.setVisible(true);

            // 获取弹窗输入结果
            Object result = currentOptionPane.getValue();
            if (result != null && result instanceof String && !((String) result).isEmpty()) {
                inputResult = (String) result;
                latch.countDown();
            }
        });
    }

    // 关闭弹窗
    private void closeOptionPane() {
        if (currentOptionPane != null) {
            SwingUtilities.invokeLater(() -> {
                JDialog dialog = (JDialog) currentOptionPane.getTopLevelAncestor();
                if (dialog != null) {
                    dialog.dispose();
                }
            });
        }
    }

    // 获取最终输入结果
    public String getInput() throws InterruptedException {
        startConsoleInput();
        startOptionPaneInput();
        // 等待任意一个输入完成,超时时间可自定义
        latch.await(5, TimeUnit.MINUTES);
        return inputResult;
    }

    // 测试主方法
    public static void main(String[] args) {
        try {
            DualInputHandler handler = new DualInputHandler();
            String result = handler.getInput();
            if (result == null || result.isEmpty() || result.equals("x")) {
                System.out.println("[注意] 将从数据库加载随机参考项");
            } else {
                System.out.println("你选择的参考项:" + result);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

关键实现说明

  1. 线程启动:使用Thread.start()真正启动并行线程,控制台输入和弹窗输入分别在独立线程中运行。
  2. Swing线程安全:通过SwingUtilities.invokeLater()确保JOptionPane在EDT线程中创建和显示,避免UI异常。
  3. 输入同步与终止:
    • 使用CountDownLatch等待第一个输入完成,一旦有输入结果就触发latch,结束等待。
    • 实现closeOptionPane()方法,当控制台有输入时,主动关闭弹窗;反之,弹窗输入完成后,控制台线程会自动退出。
  4. 线程安全的结果存储:用volatile修饰inputResult,确保多线程下的可见性。

集成到你的项目中

你可以将上述DualInputHandler类集成到你的SelectName方法中,替换原有的输入逻辑,例如:

public static String setManualname(LinkedHashMap<Character,LinkedHashMap<String,Namer>> namesList) {
    try {
        DualInputHandler handler = new DualInputHandler();
        String name = handler.getInput();

        // 保留你原有的业务逻辑判断
        if (name == null || name.equals("") || name.equals("x")) {
            System.out.println("[ATTENTION] - a random reference will be loaded from the database.");
            return "";
        } else if (name.equals("auto")) {
            return "auto";
        } else if (name.contains("x_") && name.length() > 2) {
            deleteName(namesList, name.substring(2), true);
            return setManualname(namesList);
        }
        // ... 其余业务逻辑
    } catch (InterruptedException e) {
        e.printStackTrace();
        return "";
    }
}

内容的提问来源于stack exchange,提问作者Daniel Janz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:45:59