我正在使用OpenCYC api(不过常见,除了这一点),我正在尝试创建一个名为AccessObject
的对象ao
。问题是,无论出于何种原因,都无法在主Java Swing事件线程中实例化AccessObject
。
因此,作为一种解决方法,我创建了另一个线程,它只是在AccessObject
方法中实例化run()
,并为它提供了一个getter来返回它。
所以这就是我对调用代码所拥有的:
// do something with code
AccessObject ao;
AccessObjectInstantiateThread aoThread = new AccessObjectInstantiationThread();
aoThread.start();
while(ao == null) // while loop to ensure we "wait" for aoThread to finish
{
ao = aoThread.getAoObject();
}
// Then use ao however you want
现在这段代码有效,但看起来非常荒谬。有没有更好的方法来做到这一点?请记住,我无法在主java事件线程下实例化AccessObject
。
非常感谢,Rich。
答案 0 :(得分:4)
doInBackground()
方法之前检查有效对象。 例如,
class MySwingWorker extends SwingWorker<AccessObject, Void> {
public AccessObject doInBackground() throws Exception {
// do whatever needed to create your AccessObject and check its completion
// return your AccessObject
}
}
在你的Swing代码中:
final MySwingWorker mySwingWorker = new MySwingWorker();
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChanged(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
try {
ao = mySwingWorker.get(); // ao is an AccessObject class field
// you can use ao here
} catch (whaeverExceptionYouAreTrapping e) {
// do something with exception
}
}
}
});
mySwingWorker.execute();
注意,代码注释已经过测试或编译。
编辑你也可以在你的Swing代码中简单地做一个匿名的内部类并跳过PropertyChangeListener:
new SwingWorker<AccessObject, Void>() {
public AccessObject doInBackground() throws Exception {
// do whatever needed to create your AccessObject and check its completion
// return your AccessObject
}
public void done() {
try {
ao = mySwingWorker.get(); // ao is an AccessObject class field
// you can use ao here
} catch (whaeverExceptionYouAreTrapping e) {
// do something with exception
}
}
}.execute();
答案 1 :(得分:1)
您的代码可能无效。您至少应该按如下方式声明您的变量:
volatile AccessObject ao;
原因是,您的EDT线程可能会将ao变量的值缓存为优化,并且可能看不到将ao分配给新值。
我希望此代码位于应用程序的开头,用户不会看到UI没有响应。
答案 2 :(得分:0)
理想情况下,您应该在启动线程上创建AccessObject ao
(在main()
方法中)而不是启动您的用户界面EventQueue.InvokeLater
,其中包含类似new JFrame
之类的可运行文件)直到你有了。
如果失败,请使ao
变得不稳定。您的实例化代码应该直接设置此值,而不是打扰“get”方法。它应该也可以调用带有runnable的InvokeLater来重新调整显示 - 可能启用一两个按钮,并向用户发送一条消息,表明现在可能无法实现的事情。
访问ao
的任何代码都必须准备好它可能为空的事实;您的GUI必须以两种方式工作,使用户明白其情况。每个检查或引用应如下所示:
final AccessObject local_ao = ao;
if (local_ao != null) {
// Do things. USE local_ao, NOT oa!!!
}
简而言之,总是使用local_ao,它不会改变。请记住,ao
的值可以随时更改。正如您所描述的那样,它只会从null更改为非null,并且只会执行一次,但这可能会随着代码的发展而改变。 (如果它不会发展,我的第一个建议可能是最好的。)
您的UI(EventQueue)代码不应等待任何事情。线程很痛苦,我会在UI中稍微延迟使用线程。但是你已经支付了线程的价格,所以你也可以获得你的钱。