[英]How do I read a SwingWorker's result *without* busy wait?
我正在編寫一個使用SwingWorker
執行其文件菜單操作的應用程序。 每個被調用的方法都返回一個boolean
值,告訴該操作是否成功執行。
目前我忙於等待結果,如下所示:
public boolean executeOperation() {
final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
// ..
if (aborted) {
return false;
}
// ..
return true;
}
};
worker.execute();
// busy wait
while (!worker.isDone())
;
try {
return worker.get().booleanValue();
} catch (Exception e) {
// handle exceptions ..
return false;
}
}
是否有一種較少投票的方式來解決這個問題?
直接使用worker.get()
是行不通的,因為它會阻止EDT,等待任務完成 - 這意味着即使我在SwingWorker
打開的對話框也不會被繪制。
編輯:如果可能的話,我想避免方法(或工人)異步地傳達他們的結果。 我正在實現幾個相互依賴的簡短方法(文件 - >打開,新建,關閉,保存,另存為,退出)(即當試圖退出,退出呼叫關閉,關閉可能會調用保存,保存可能會調用保存如)。 異步解決這個問題似乎使代碼變得更加復雜。
SwingWorker的目的正是在后台啟動一些任務,而不是阻止EDT。 要么你想要同步的東西,要么你想要的東西阻止EDT,或者你想要異步的東西,后台任務應該使用SwingWorker的publish
方法更新它的狀態。
您可以在任務運行時顯示帶有進度條的阻止模式對話框,並在任務完成后隱藏它。
另一種方法是阻塞一段時間,希望任務快速完成,然后備份到異步方式。 這可以使用get
方法將超時作為參數來完成。
您可以使用異步范例。 查看Observer / Observable並使用該作業將結果傳回給當前正在進行輪詢的對象。
直接使用
worker.get()
是行不通的,因為它會阻止EDT,等待任務完成 - 這意味着即使我在SwingWorker
打開的對話框也不會被繪制。
他們也沒有使用當前的代碼。 忙碌的等待會阻塞EDT,就像調用worker.get()
一樣 - 只有一個事件調度線程,如果該線程在循環中旋轉或等待鎖定,則SwingWorker
中的對話框也被阻止。 這里的問題是,如果一個方法在EDT上運行,它根本無法從異步操作(不占用EDT)返回一個值給它的調用者。
對完成的異步處理作出反應的正確方法是覆蓋SwingWorker
的done()
方法。
另請參閱http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html以獲取更多信息。
上面幾個人提到的一種方法是覆蓋SwingWorker的done方法。 但是,如果出於某種原因,您希望在SwingWorker之外和調用代碼中發布SwingWorker代碼,則可以利用SwingWorker的屬性更改支持。 只需將一個PropertyChangeListener添加到SwingWorker並偵聽屬性名稱為“state”的state屬性。 然后,您可以使用其getState()方法提取SwingWorker的狀態。 完成后,它將返回SwingWorker.StateValue枚舉的DONE值。 例如(從我在SO的另一個帖子中給出的答案):
if (turn == white) {
try {
final SwingWorker<Move, Void> mySwingWorker = new SwingWorker<Move, Void>() {
@Override
protected Move doInBackground() throws Exception {
Engine e = new Engine(); // Engine is implemented by runnable
e.start();
Move m = e.getBestMove(board);
return m;
}
};
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (StateValue.DONE == mySwingWorker.getState()) {
try {
Move m = mySwingWorker.get();
// TODO: insert code to run on the EDT after move determined
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
});
mySwingWorker.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
當我想要一個函數返回一個將在swing工作者中計算的值時,我遇到了類似的問題。 我不想簡單地讓那個線程阻止EDT。 我也不想阻止它。 所以我使用了這樣的信號量:
public boolean executeOperation() {
final Semaphore semaphore = new Semaphore(1);
semaphore.acquire(1); // surround by try catch...
final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
// ..
if (aborted) {
semaphore.release();
return false;
}
// ..
semaphore.release();
return true;
}
};
worker.execute();
try {
semaphore.tryAcquire(1, 600, TimeUnit.SECONDS); // awakes when released or when 10 minutes are up.
return worker.get().booleanValue(); // blocks here if the task doesn't finish in 10 minutes.
} catch (Exception e) {
// handle exceptions ..
return false;
}
}
我想這對所有情況都不理想。 但我認為這是一種對我來說非常有用的替代方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.