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

Java GUI监听器中Thread.sleep致界面冻结问题及Shell命令执行咨询

解决你的两个Java问题:Swing界面冻结+执行Shell命令

嘿,我来帮你搞定这两个问题!先从你遇到的倒计时界面冻结说起,再讲Java执行Shell命令的方法。

一、解决Swing倒计时界面冻结的问题

你遇到的界面冻结是Swing单线程模型导致的:Swing的所有UI更新和事件处理都在**事件调度线程(EDT)**里执行。你在ActionListener的actionPerformed方法里直接用Thread.sleep(1000),会把EDT线程阻塞住——这个线程被卡住了,自然没法更新界面、响应其他按钮操作,所以界面就冻住了。

解决方案:用javax.swing.Timer替代Thread.sleep

Swing Timer专门用来在EDT线程里定时执行任务,不会阻塞UI线程。下面是修改后的按钮点击事件代码:

butt1.addActionListener(new ActionListener(){
    private int remainingSeconds = 600; // 10分钟=600秒
    private Timer countdownTimer;

    public void actionPerformed(ActionEvent evt){
        // 避免重复点击启动多个定时器
        if(countdownTimer != null && countdownTimer.isRunning()){
            return;
        }

        countdownTimer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                remainingSeconds--;
                if(remainingSeconds <= 0){
                    countdownTimer.stop();
                    lab1.setText("时间到!");
                    // 这里可以加闹钟触发的逻辑,比如播放声音
                } else {
                    // 格式化显示为分:秒,比如9:59
                    int minutes = remainingSeconds / 60;
                    int seconds = remainingSeconds % 60;
                    lab1.setText(String.format("%d:%02d", minutes, seconds));
                }
            }
        });
        countdownTimer.start();
    }
});

这样修改后,定时器每隔1秒在EDT线程里触发一次更新,既不会阻塞界面,还能正确刷新剩余时间。另外还加了重复点击的判断,防止启动多个定时器。

二、Java中执行Shell命令的方法

Java有两种常用的方式执行Shell命令:Runtime.getRuntime().exec()和ProcessBuilder,后者更推荐,因为更灵活。

1. 使用Runtime.getRuntime().exec()

这是比较传统的方式,适合简单命令:

try {
    // 执行ls命令(Windows换成dir)
    Process process = Runtime.getRuntime().exec("ls");
    
    // 读取命令输出
    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
    
    // 等待命令执行完成,获取退出码
    int exitCode = process.waitFor();
    System.out.println("命令执行完成,退出码:" + exitCode);
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}

注意:如果命令有参数,最好用字符串数组的形式传递,比如exec(new String[]{"ls", "-l"}),避免空格解析问题。

2. 使用ProcessBuilder(推荐)

ProcessBuilder提供了更多控制,比如设置工作目录、环境变量,还能合并错误流和输出流:

try {
    // 构建命令,比如执行ping百度
    ProcessBuilder pb = new ProcessBuilder("ping", "www.baidu.com");
    // 设置工作目录(可选)
    pb.directory(new File("/your/work/dir"));
    // 合并错误流到输出流,方便统一读取
    pb.redirectErrorStream(true);
    
    Process process = pb.start();
    
    // 读取输出
    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
    
    int exitCode = process.waitFor();
    System.out.println("命令执行完成,退出码:" + exitCode);
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}

你的原代码整理

最后把你提供的代码用规范的代码块整理一下:

public class Budik extends JFrame{ 
    private JLabel lab1,lab2; 
    private JButton butt1,butt2,butt3; 
    private JTextField t1,t2; 
    private JSpinner spinner; 
    private JCheckBox cx1,cx2; 
    private JList list; 
    private JPanel p1,p2,p3,p4,p5; 
    private JPasswordField pass1,pass2; 

    public static void main(String[] args) { 
        Budik okno = new Budik(); 
        okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        okno.setVisible(true); 
        okno.pack(); 
        okno.setLocationRelativeTo(null); 
        okno.setResizable(false); 
    } 

    public Budik() { 
        super("Countdown"); 
        setLayout(new BorderLayout()); 

        // p1 
        GridLayout el = new GridLayout(2,1); 
        p1 = new JPanel(el); 
        add(p1,BorderLayout.NORTH); 
        lab1 = new JLabel("Welcome",SwingConstants.CENTER); 
        lab2 = new JLabel("Created by WajFaj",SwingConstants.CENTER); 
        lab1.setFont(new Font("Serif", Font.PLAIN, 36)); 
        p1.add(lab1); 
        p1.add(lab2); 

        //p2 
        p2 = new JPanel(); 
        add(p2,BorderLayout.WEST); 
        butt1 = new JButton("START"); 
        p2.add(butt1); 

        //p3 
        p3 = new JPanel(); 
        add(p3,BorderLayout.CENTER); 
        butt2 = new JButton("STOP"); 
        p3.add(butt2); 

        //p4 
        p4 = new JPanel(); 
        add(p4,BorderLayout.EAST); 
        butt3 = new JButton("RESET"); 
        p4.add(butt3); 

        //p5 
        p5 = new JPanel(); 
        add(p5,BorderLayout.SOUTH); 

        butt1.addActionListener(new ActionListener(){ 
            public void actionPerformed(ActionEvent evt){ 
                for(int i=600; i>0;i-- ){ 
                    try{ 
                        Thread.sleep(1000); 
                        String cc = ""+i; 
                        lab1.setText(cc); 
                    } catch(InterruptedException e){ 
                        System.out.println("Chyba!"); 
                    } 
                } 
            } 
        }); 
    }
}

内容的提问来源于stack exchange,提问作者Zdeněk Krast

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:09:00