Java Swing 组件更新线程冲突问题

Sep 6, 2021 阅读(22)

标签: Java

先看一下以下更新组件的代码:

import javax.swing.*;
import java.util.concurrent.TimeUnit;

public class HelloLabel {

    public static void main(String[] args) throws InterruptedException {
        JFrame frame = new JFrame("Hello Swing");
        JLabel label = new JLabel("3 秒钟后会发生了变化");
        frame.add(label);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.setVisible(true);

        TimeUnit.SECONDS.sleep(3);
        label.setText("...  ^_^  ...");
    }
}

该代码意图3秒后更新label标签的显示内容。 

直接在main现在线程中对 GUI 组件操作可能会造成冲突和死锁,因为Swing 它有自己专用的线程来接收UI事件并更新屏幕。


修改上述代码,使用 swing 线程来更新代码如下(不是最终代码):

import javax.swing.*;
import java.util.concurrent.TimeUnit;

public class SubmitLabelManipulationTask {
    public static void main(String[] args) throws InterruptedException {
        JFrame frame = new JFrame("Swing Hello");
        JLabel label = new JLabel("3 秒钟后会发生了变化");
        frame.add(label);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.setVisible(true);

        TimeUnit.SECONDS.sleep(3);
        // 通过 Swing 的事件分发线程提交要执行的任务(任务会放置到待执行队列中,最终将会得到执行)。
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                label.setText("...  ^_^  ...");
            }
        });

    }
}


要想不会发生冲突,则需要程序中的所有 UI 操作都遵守这种通过 SwingUtilities.invokeLater() 方式来提交操作。


最终代码:

import javax.swing.*;
import java.awt.*;
import java.util.concurrent.TimeUnit;

/**
 * 程序中的所有 UI 操作都遵守这种通过 SwingUtilities.invokeLater() 方式来提交操作
 */
public class SubmitSwingProgram extends JFrame {
    static SubmitSwingProgram ssp;

    JLabel label;

    public SubmitSwingProgram() throws HeadlessException {
        super("Hello Swing");

        label = new JLabel("3 秒钟后会发生了变化");
        add(label);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(300, 300);
        setVisible(true);
    }

    public static void main(String[] args) throws InterruptedException {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                ssp = new SubmitSwingProgram();
            }
        });

        TimeUnit.SECONDS.sleep(1);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                ssp.label.setText("\t ^_^   修改啦");
            }
        });
    }
}


MongoDB学习园