2

我有一个非 GUI 线程,它使用

java.awt.EventQueue.invokeLater(new Runnable() {

    public void run() {
        cardReadPunchGUI = new IBM1622GUI();  // instantiate
        cardReadPunchGUI.setVisible(true);
    }
});

IBM1622GUI 的构造函数的一部分为自己实例化了一个“模型”,我的非 GUI 线程需要访问它:

cardReadPunch = IBM1622GUI.getModel();

我的非 GUI 线程与“稍后调用”的新 GUI 同步的正确方法是什么?(当然,如果没有同步,IBM1622GUI.getModel()只会返回 null。)

4

4 回答 4

4

利用

javax.swing.SwingUtilities.invokeAndWait(Runnable doRun);

反而。

导致 doRun.run() 在 AWT 事件分派线程上同步执行。此调用会阻塞,直到所有待处理的 AWT 事件都已处理并且(然后)doRun.run() 返回。

于 2011-08-03T03:10:52.710 回答
2

我建议您与非 GUI 和 GUI 线程共享一个初始化为 1的CountDownLatch 。

非 GUI 线程在启动时会调用latch.await(),这会将其置于阻塞状态。

GUI 线程将latch.countDown()在其完成初始化后调用,之后非 GUI 线程将从 await 调用中退出并且两个线程同步。

于 2011-08-03T03:12:26.357 回答
2

好吧,如果您可以访问它,您总是可以将该特定逻辑移到 Swing 线程之外并移到调用invokeLater. IBM622GUI假设构造函数 for表现良好,那么在 Swing 线程之外执行您正在执行的操作并没有什么不安全的。

除此之外,您可以使用各种其他机制。

  1. 你可以使用invokeAndWait, 就像 cgull 打败我说的那样。
  2. 你可以让runnable设置a的值而不是直接引用,并通过调用future的方法Future阻塞主线程。get
  3. 您可以在主线程和Swing 线程中CountDownLatch拥有一个起始计数为 1的值。await()countDown()

有很多很多实用程序可以帮助进行同步。

于 2011-08-03T03:12:50.380 回答
1

通常,您将参数传递给线程。在后台运行逻辑。然后使用 SwingUtilities.invokeLater() 回发您需要对任何这些对象或 UI 线程上的 UI 元素进行的任何修改。通常我会创建一个简单的实用程序,它允许我指定应该在后台线程上运行什么,以及应该在 UI 线程上运行什么。SwingWorker 是您可以使用的东西,尽管我觉得使用起来非常痛苦。像这样简单的东西:

new AsyncThread<Param,T>() {
   public T executeInBackground( Param param ) {
      // do something long running
      T result = // do something long running;
      return T;
   }

   public void executeOnUI( T result ) {
      // update the UI here, or modify the model, etc.
   }
}.execute( param );

AsyncThread 将在另一个线程上执行 executeInBackground() 方法。然后在内部它会使用 SwingUtilities.invokeLater() 发回 UI 线程。然后 executeOnUI 将在 UI 线程上运行。execute() 方法可以创建一个线程以在后台运行、处理异常等。

我会让 GUI 可能启动线程,并让 GUI 将它的模型或它需要的任何部分传递给线程。而不是反过来。这样,您可以让 UI 提供有关正在运行的后台线程的反馈。但是,您不能让后台线程接触(写入/修改/更改)UI 线程将同时读取/写入的模型的成员。因此,如果您打算修改模型以响应后台线程,请将其发布回 UI 线程以确保安全。

于 2011-08-03T03:11:45.190 回答