Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我的GUI冻结了_Java_Multithreading_User Interface_Swing_Freeze - Fatal编程技术网

Java 我的GUI冻结了

Java 我的GUI冻结了,java,multithreading,user-interface,swing,freeze,Java,Multithreading,User Interface,Swing,Freeze,我有点不明白:我的Swing GUI包含一个“播放”和“暂停”按钮。我还有一个静态变量,用于定义“开”和“关”状态。(主程序生成GUI)。 通过点击“play”,我将静态变量的状态更改为“on”,并在一个线程中启动一个耗时的过程,该线程也会修改GUI。只要静态变量在同一进程中是“开”循环。单击“暂停”会将静态变量更改为关闭。 但通过单击“播放”,GUI将冻结,因此: GUI不会更新 无法使用我的“暂停”按钮“暂停”进程 我听说过EDT和SwingWorker,但我相信你有一个简单的方法 感谢您的

我有点不明白:我的Swing GUI包含一个“播放”和“暂停”按钮。我还有一个静态变量,用于定义“开”和“关”状态。(主程序生成GUI)。 通过点击“play”,我将静态变量的状态更改为“on”,并在一个线程中启动一个耗时的过程,该线程也会修改GUI。只要静态变量在同一进程中是“开”循环。单击“暂停”会将静态变量更改为关闭。 但通过单击“播放”,GUI将冻结,因此:

  • GUI不会更新
  • 无法使用我的“暂停”按钮“暂停”进程
  • 我听说过EDT和SwingWorker,但我相信你有一个简单的方法


    感谢您的帮助,请原谅我的英语不好…

    问题是,您在负责更新GUI的同一线程上进行了大量耗时的工作。SwingWorker允许您将耗时的任务移动到单独的执行线程,从而使UI线程不受限制地执行任务

    然而,它确实增加了另一个复杂性:亲和性。对UI组件调用方法通常需要从UI线程执行。因此,您需要使用特殊功能从工作线程返回UI线程。SwingWorker也给你这种能力


    我建议您通读一遍。

    您不应该在Swing的事件处理程序中启动长时间运行的进程,因为它会冻结您的GUI,您现在知道了。:)从一个新的线程开始。如果您计划从工作线程操作GUI(因为Swing不是线程安全的),则只需使用
    SwingWorker

    这是一个非常简单的原因:当Java正在处理耗时的进程时,它无法更新GUI。解决方案:在单独的线程中运行耗时的进程。编程的方法有很多种,这可能在某种程度上取决于您的程序是如何编写的。

    您需要阅读以了解EDT和Swingworker是如何操作的

    所有GUI更新都在EDT上执行,因此当您单击GUI组件时,此调用的任何方法都将在EDT上执行。如果这是一个耗时的过程,那么这将阻止EDT执行任何进一步的GUI更新。因此,您的GUI处于冻结状态,无法单击“暂停”按钮

    您需要使用SwingWorker在另一个线程上执行耗时的进程。我上面提供的链接详细介绍了如何执行此操作。

    事件调度线程(EDT)是唯一可以安全读取或更新GUI的线程

    暂停按钮应在事件分派线程中设置开/关变量

    耗时的操作和循环不应在EDT中。(循环也不应该连续运行,除了检查变量之外什么都不做,否则它很容易占用所有的CPU。如果它没有其他事情要做,应该检查,然后调用
    Thread.sleep()
    一段时间(比如100ms)。)

    如果您可以证明on/off变量被设置为off,但它始终被读取为on,那么可能是变量的值没有从EDT复制到工作线程。使其
    易失性
    ,或
    同步
    对其的访问,或使用
    原子引用
    ,或使用
    SwingUtilities.invokeAndWait()
    在EDT中读取它

    SwingWorker
    可能是最简单的方法。在
    doInBackground()
    方法中执行耗时的操作和开/关检查,并在
    done()
    方法中执行GUI更新

    public enum State {
        RUNNING, STOPPED
    }
    
    public class ThreadSafeStateModel {
        private State state = State.STOPPED;
    
        public synchronized void stop() {
            state = State.STOPPED;
        }
    
        public synchronized void start() {
            state = State.RUNNING;
        }
    
        public boolean isRunning() {
            return state == State.RUNNING;
        }
    }
    
    public class ExpensiveProcessWorker extends SwingWorker<Void, Void> {
    
        private final ThreadSafeStateModel model;
    
        public ExpensiveProcessWorker(ThreadSafeStateModel model) {
            this.model = model;
        }
    
        @Override // Runs in background
        protected Void doInBackground() throws Exception { 
            while (model.isRunning()) {
                // do one iteration of something expensive
            }
            return null;
        }
    
        @Override // Runs in event dispatch thread
        protected void done() { 
            // Update the GUI
        }
    }
    
    public class StopButton extends JButton {
        public StopButton(final ThreadSafeStateModel model) {
            super(new AbstractAction("Stop") {
                @Override
                public void actionPerformed(ActionEvent e) {
                    model.stop();
                }
            });
        }
    }
    
    public class StartButton extends JButton {
        public StartButton(final ThreadSafeStateModel model) {
            super(new AbstractAction("Start") {
                @Override
                public void actionPerformed(ActionEvent e) {
                    model.start();
                    new ExpensiveProcessWorker(model).execute();
                }
            });
        }
    }
    
    公共枚举状态{
    跑,停
    }
    公共类ThreadSafeStateModel{
    私有状态=State.STOPPED;
    公共同步无效停止(){
    state=state.STOPPED;
    }
    公共同步的void start(){
    state=state.RUNNING;
    }
    公共布尔值正在运行(){
    返回状态==state.RUNNING;
    }
    }
    公共类ExpensiveProcessWorker扩展SwingWorker{
    私有最终ThreadSafeStateModel模型;
    public ExpensiveProcessWorker(ThreadSafeStateModel模型){
    this.model=模型;
    }
    @覆盖//在后台运行
    受保护的Void doInBackground()引发异常{
    while(model.isRunning()){
    //做一次昂贵的迭代
    }
    返回null;
    }
    @重写//在事件分派线程中运行
    受保护的void done(){
    //更新GUI
    }
    }
    公共类StopButton扩展了JButton{
    公共停止按钮(最终ThreadSafeStateModel型号){
    超级(新抽象动作(“停止”){
    @凌驾
    已执行的公共无效操作(操作事件e){
    model.stop();
    }
    });
    }
    }
    公共类StartButton扩展了JButton{
    公共启动按钮(最终ThreadSafeStateModel模型){
    超级(新抽象动作(“开始”){
    @凌驾
    已执行的公共无效操作(操作事件e){
    model.start();
    新ExpensiveProcessWorker(model).execute();
    }
    });
    }
    }
    

    (根据实际的应用程序,我们可以做很多工作来清理这个问题,但您已经知道了。)

    谢谢,David,一切正常,运行良好。但有一件事:我不需要使用done()方法来刷新GUI。我在doInBackground()方法中成功地做到了这一点。你对此有什么想法吗?嘿,杰里米——一般来说,更新
    doInBackground()
    中的UI通常会起作用,但你不能依赖它。UI总是在事件分派线程中绘制,UI模型总是在事件分派线程中读取,因此只在事件分派线程中写入UI模型更安全。例如,如果
    TableModel
    中的行数在事件分派线程之外发生更改,则很有可能在
    @Override
    public void actionPerformed(ActionEvent e) {
         new Thread() {
            public void run() {
                //your code which runs on click event
            }
        }.start();
    
    }