2009-05-27 116 views
2

我有2個進程在我的swing應用程序中執行,一個用於填充列表,另一個用於對列表中的每個元素執行操作。我剛剛將這兩個進程移到了Swingworker線程中,以便在執行任務時停止GUI鎖定,並且因爲我需要對多個列表執行這組操作,所以併發性在第一個並不會是一個壞主意地點。然而,當我剛剛跑調度Swingworker線程

fillList.execute();
doStuffToList.execute();

doStuffToList線程在空列表上運行(duh ...)。我如何讓第二個過程等到第一個過程完成?我想我可以在第一個過程結束時嵌套第二個過程,但我不知道,這似乎是不好的做法。

+1

聽起來像一個的BlockingQueue有可能會有所幫助(http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html)。 – 2009-05-27 14:56:08

回答

1

像這樣的事情會這樣做,我想?

boolean listIsFull=false; 
class FillListWorker extends SwingWorker<Foo,Bar> 
{ 
    ... 
    protected void done() 
    { 
     synchronized (listYouveBeenFilling) 
     { 
      listIsFull=true; 
      listYouveBeenFilling.notifyAll(); 
     } 
    } 
    ... 
} 

class DoStuffToListListWorker extends SwingWorker<Foo,Bar> 
{ 
    ... 
    protected Foo doInBackground() 
    { 
     synchronized (listYouveBeenFilling) 
     { 
      while (!listIsFull) 
      { 
       try 
       { 
        listYouveBeenFilling.wait(); 
       } 
       catch (InterruptedException ie) 
       { 
        // Don't worry, we'll just wait again 
       } 
      } 
     } 
    } 
    ... 
} 
+0

我喜歡這個解決方案,但是它並不適合我,因爲`listIsFull`必須是最終的,因爲它是從一個內部類訪問的...這使得它不可能修改後面的值你正試圖做。 – The111 2012-04-08 00:20:02

+0

如果你在一個方法中定義它,它只需要是'final'。如果您將其定義爲外部類的成員字段,則一切都會好的。 – 2012-04-08 07:46:38

-1

要按順序執行兩個進程,傳統上只需要在另一個(!)之後調用一個方法。

fillList(); 
doStuffToList(); 

或許是這樣的:

doStuffToList(fillList()); 

如果你是在一次處理一個,你可能想兩個線程之間用BlockingQueue。你可以進一步做多個do-stuff線程。

就AWT事件調度線程(EDT)而言,它只是分離一個沒有阻塞的動作,並在稍後得到通知。

+0

這錯過了SwingWorker#execute立即返回的意思。 OP清楚地知道如何一個接一個地調用一個函數。 – 2014-03-27 20:18:59

1

如何告訴第二個進程等到第一個進程完成?我想我可以在第一個過程結束時嵌套第二個過程,但我不知道,這似乎是不好的做法。

你看過嗎?使用可調整的&期貨代替嗎?他們聽起來像是一個很好的匹配(讓doStuffToList在Future.get()上工作,而不是實際的列表,所以它會在調用get時做好準備),除了整個迴轉工具業務之外..(考慮這個建議,而不是一個答案)

0

我們有這樣的事情:

private SwingWorkerExecutor swingWorkerExecutor; 

//... 

protected void runChain(List<SwingWorker<Void>> chainWorkers, 
         final SwingWorkerExecutor.RunAfter<Void> runAfter, 
         final SwingWorkerExecutor.RunOnError runOnError) 
{ 
    final List<SwingWorker<Void>> remainingWorkers = 
     chainWorkers.subList(1, chainWorkers.size()); 
    SwingWorkerExecutor.RunAfter<Void> chainRunAfter; 
    if (chainWorkers.size() > 1) 
    { 
     chainRunAfter = new SwingWorkerExecutor.RunAfter<Void>() 
     { 
      @Override 
      public void run(Void value) 
      { 
       runChain(remainingWorkers, runAfter, runOnError); 
      } 
     }; 
    } 
    else 
    { 
     chainRunAfter = runAfter; 
    } 

    currentWorker = chainWorkers.get(0); 

    swingWorkerExecutor.execute(currentWorker, chainRunAfter, runOnError); 
} 

這是非常簡單的,海事組織,因爲在我們的例子中SwingWorkerExecutor實際上包含了所有的難以理解的東西:

public class DefaultSwingWorkerExecutor implements SwingWorkerExecutor 
{ 
    @Override 
    public <T> void execute(SwingWorker<T, ?> worker, RunAfter<T> after, 
          RunOnError onError) 
    { 
     worker.addPropertyChangeListener(
      new RunAfterHandler<T>(worker, after, onError)); 
     worker.execute(); 
    } 

    private static class RunAfterHandler<T> implements PropertyChangeListener 
    { 
     private final SwingWorker<T, ?> worker; 
     private final RunAfter<T> after; 
     private final RunAfter<Throwable> onError; 

     protected RunAfterHandler(SwingWorker<T, ?> worker, RunAfter<T> after, 
            RunOnError onError) 
     { 
      this.worker = worker; 
      this.after = after; 
      this.onError = onError; 
     } 

     @Override 
     public void propertyChange(PropertyChangeEvent evt) 
     { 
      if ("state".equals(evt.getPropertyName()) && 
       evt.getNewValue() == SwingWorker.StateValue.DONE) 
      { 
       if (worker.isCancelled()) 
       { 
        return; 
       } 

       try 
       { 
        after.run(worker.get()); 
       } 
       catch (InterruptedException e) 
       { 
        Thread.currentThread().interrupt(); 
       } 
       catch (ExecutionException e) 
       { 
        onError.run(e); 
       } 
      } 
     } 
    } 
} 

有一些缺少的接口whic h應該非常直截了當地在這裏看不到它們。

我們真正的部署SwingWorkerExecutor使用注入的ExecutorService而不是默認的執行(這減少了我們爲單個應用程序需要的線程池的數量)。但是我們引入SwingWorkerExecutor的真正原因是它簡化並標準化了處理SwingWorker的成功和錯誤條件,並且還允許替換單元測試的邏輯(我相信你知道,如果它們是單線程的,它會簡單得多。)正如你所看到的,你會在done()中的每一個SwingWorker中通常需要一堆樣板文件,所以我們將done()工作移到了回調中,而不是這樣做。

副作用就像在一個鏈中運行多個Swing工作者一樣,很容易實現。