![](/img/trans.png)
[英]Future waiting for FixedThreadPool is returning before all Threads finish
[英]Waiting for a cancelled future to actually finish
我有一個SwingWorker
調用一些不檢查線程中斷的代碼。 在調用worker.cancel(true)
, worker.get()
方法將立即拋出CancellationException
(正如它應該的那樣)。 但是,由於后台任務的代碼從不檢查其線程是否被中斷,因此它很樂意繼續執行。
是否存在等待后台任務實際完成的標准方法? 我希望顯示一個“正在取消...”消息或類似的東西,並阻止任務終止。 (我確信如果有必要,我可以在工人類中使用標志來完成此操作,只需查找其他任何解決方案。)
我玩了一下這個,這就是我想出來的。 我正在使用CountDownLatch
並基本上將其await()
方法暴露為我的SwingWorker
對象上的方法。 仍在尋找任何更好的解決方案。
final class Worker extends SwingWorker<Void, Void> {
private final CountDownLatch actuallyFinishedLatch = new CountDownLatch(1);
@Override
protected Void doInBackground() throws Exception {
try {
System.out.println("Long Task Started");
/* Simulate long running method */
for (int i = 0; i < 1000000000; i++) {
double d = Math.sqrt(i);
}
return null;
} finally {
actuallyFinishedLatch.countDown();
}
}
public void awaitActualCompletion() throws InterruptedException {
actuallyFinishedLatch.await();
}
public static void main(String[] args) {
Worker worker = new Worker();
worker.execute();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
System.out.println("Cancelling");
worker.cancel(true);
try {
worker.get();
} catch (CancellationException e) {
System.out.println("CancellationException properly thrown");
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
System.out.println("Awaiting Actual Completion");
try {
worker.awaitActualCompletion();
System.out.println("Done");
} catch (InterruptedException e) {
}
}
}
與標准或現成方法最接近的是SwingWorker
提供的progress
屬性和/或發布/進程方法對。 您可以在方法結束時將其設置為“我已完成”值,以指示后台工作已完成。 等待swing工作者的線程可以發出“正在取消...”消息並定期檢查進度以查看它是否已完成。 如果等待線程是擺動EDT,那么您將需要使用Timer定期檢查progress屬性並在完成后清除取消消息。
下面是一些運行頑固后台線程的示例代碼,該線程被取消,然后等待進度達到100。
@Test
public void testSwingWorker()
{
SwingWorker worker = new SwingWorker() {
@Override
protected void process(List chunks)
{
for (Object chunk : chunks)
{
System.out.println("process: "+chunk.toString());
}
}
@Override
protected void done()
{
System.out.println("done");
}
@Override
protected Object doInBackground() throws Exception
{
// simulate long running method
for (int i=0; i<1000000000; i++)
{
double d = Math.sqrt(i);
}
System.err.println("finished");
publish("finished");
setProgress(100);
return null;
}
};
Thread t = new Thread(worker);
t.start();
try
{
worker.get(1, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
}
catch (ExecutionException e) {
}
catch (TimeoutException e) {
}
worker.cancel(true);
// now wait for finish.
int progress = 0;
do
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
progress = worker.getProgress();
System.out.println(String.format("progress %d", progress));
}
while (progress<100);
}
另一種方法是使用publish\\process
方法對來推送一個特殊值,指示后台線程已完成EDT。 然后,您在SwingWorker中的process
覆蓋方法將獲取此特殊值並隱藏“正在取消...”消息。 這樣做的好處是不需要輪詢或定時器。 示例代碼顯示盡管done
取消任務后立即調用done
,但即使取消任務,發布/處理方法對仍然有效。
受Paul Blessing解決方案的啟發,我將它改進了一點,成為一個類,你可以通過子類來獲得所需的功能:
class AwaitingWorker<T,V> extends SwingWorker<T, V> {
private final CountDownLatch actuallyFinishedLatch = new CountDownLatch(1);
/**
* Override this to do something useful
*/
protected abstract void performOperation();
@Override
protected final T doInBackground() throws Exception {
try {
return performOperation();
} finally {
actuallyFinishedLatch.countDown();
}
}
public void awaitActualCompletion() throws InterruptedException {
actuallyFinishedLatch.await();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.