Java线程如何与invokeLater()同步?

时间:2011-08-03 03:01:01

标签: java swing synchronization invokelater invokeandwait

我有一个使用

启动JFrame的非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 个答案:

答案 0 :(得分:4)

使用

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

代替。

  

导致doRun.run()在AWT事件上同步执行   调度线程。此调用将阻塞,直到所有挂起的AWT事件都有   已处理完毕,然后(然后)doRun.run()返回。

答案 1 :(得分:2)

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

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

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

答案 2 :(得分:2)

好吧,如果你有权访问它,你总是可以将那个特定的逻辑移到Swing线程之外,然后移到调用invokeLater的线程上。假设IBM622GUI的构造函数表现良好,那么从Swing线程做你正在做的事情并没有什么不安全的。

除此之外,你可以利用各种其他机制。

  1. 你可以使用invokeAndWait,因为cgull打败我说。
  2. 您可以让runnable设置Future的值而不是直接引用,并通过调用future get方法阻止主线程。
  3. 您的主线程上CountDownLatch的起始计数为1 await(),而Swing线程中的countDown()可以为<{1}}。
  4. 有许多实用程序可以帮助进行同步。

答案 3 :(得分:1)

通常将参数传递给Thread。在后台运行逻辑。然后使用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线程以确保安全。