我有一个使用
启动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。)
答案 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线程做你正在做的事情并没有什么不安全的。
除此之外,你可以利用各种其他机制。
invokeAndWait
,因为cgull打败我说。Future
的值而不是直接引用,并通过调用future get
方法阻止主线程。CountDownLatch
的起始计数为1 await()
,而Swing线程中的countDown()
可以为<{1}}。有许多实用程序可以帮助进行同步。
答案 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线程以确保安全。