java - 如何在 java swing 中以线程安全的方式初始化 gui 对象?

标签 java multithreading swing thread-safety event-dispatch-thread

我正在阅读 Thinking in Java,作者强调 main 方法不应该调用 swing 方法。作为该实践的示例,他展示了以下代码片段(可在他的网页上找到):

//: gui/SubmitSwingProgram.java
import javax.swing.*;
import java.util.concurrent.*;

public class SubmitSwingProgram extends JFrame {
  JLabel label;
  public SubmitSwingProgram() {
    super("Hello Swing");
    label = new JLabel("A Label");
    add(label);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(300, 100);
    setVisible(true);
  }
  static SubmitSwingProgram ssp;
  public static void main(String[] args) throws Exception {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() { ssp = new SubmitSwingProgram(); }
    });
    TimeUnit.SECONDS.sleep(1);
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        ssp.label.setText("Hey! This is Different!");
      }
    });
  }
} ///:~

然后通过 invokeLater 方法创建和初始化 gui 对象,使其成为线程安全的。但是几页之后,作者给出了以下代码:

//: gui/Button2.java
// Responding to button presses.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static net.mindview.util.SwingConsole.*;

public class Button2 extends JFrame {
  private JButton
    b1 = new JButton("Button 1"),
    b2 = new JButton("Button 2");
  private JTextField txt = new JTextField(10);
  class ButtonListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      String name = ((JButton)e.getSource()).getText();
      txt.setText(name);
    }
  }
  private ButtonListener bl = new ButtonListener();
  public Button2() {
    b1.addActionListener(bl);
    b2.addActionListener(bl);
    setLayout(new FlowLayout());
    add(b1);
    add(b2);
    add(txt);
  }
  public static void main(String[] args) {
    run(new Button2(), 200, 150);
  }
} ///:~

SwingConsole 在哪里:

//: net/mindview/util/SwingConsole.java
// Tool for running Swing demos from the
// console, both applets and JFrames.
package net.mindview.util;
import javax.swing.*;

public class SwingConsole {
  public static void
  run(final JFrame f, final int width, final int height) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        f.setTitle(f.getClass().getSimpleName());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(width, height);
        f.setVisible(true);
      }
    });
  }
} ///:~

因此与前面的示例相反,在主方法/主线程中创建并初始化实现 JFrame 的对象。

那么我的问题是: (1) 第二个例子是错误的还是第一个被夸大了? (2) 仅在 setVisible 调用之后和该语句之前通过 invokeLater 调用 swing 方法是否足够,在主线程中调用 swing 方法是安全的?

最佳答案

第二个例子是错误的。必须从事件分派(dispatch)线程创建和使用 Swing 组件。参见 https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html .

引自 the javadoc :

Calls to an application's main method, or methods in Applet, are not invoked on the event dispatching thread. As such, care must be taken to transfer control to the event dispatching thread when constructing and showing an application or applet.

(强调我的)

关于java - 如何在 java swing 中以线程安全的方式初始化 gui 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26834078/

相关文章:

java - Console() 运行时错误

java - 包含不适用于 ("\\+"的方法)

Java何时启动新线程?

java - 多线程中的cookie覆盖

c++ - 线程上的 Qt 信号槽,这是安全的方法吗?

java - 减少 Java 应用程序中的 CPU 使用

java - Log4j2 HTMLLayout 配置和输出

java - 使用二维数组和 JfreeChart 制作散点图

java - 在 weblogic 12.2.1.3 上创建 javax.xml.ws.Service 实例时出现 NullPointerException

java - 将行保持在同一位置的 View 中