2011-09-08 50 views
6

我正在編寫一個應用程序,它使用SwingWorker執行其文件菜單操作。每個調用的方法返回一個值boolean,該值告訴操作是否成功執行。如何讀取SwingWorker的結果*而無需等待?

目前我使用的繁忙等待結果,這樣的:

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中打開對話框不會得到畫。

編輯:如果可能,我想避免該方法(或工作人員)異步溝通其結果。我正在執行幾個相互依賴的簡短方法(文件 - >打開,新建,關閉,保存,另存爲,退出)(即當試圖退出,退出調用close,close可能調用save,save可能調用save如)。異步解決似乎會使代碼變得更加複雜。

+0

您可以隨時在循環中放入Thread.sleep(100)。 –

+2

這並不會改變您對結果進行輪詢的事實,而不是讓對象進行計算來告訴您何時完成。 – mcfinnigan

回答

6

SwingWorker的要點恰恰是在後臺啓動一些任務,並且不會阻止EDT。無論你想要什麼東西都是同步的,無論你嘗試什麼,EDT都會被阻塞,或者你想要異步的東西,後臺任務應該使用SwingWorker的publish方法更新其狀態。

您可以在任務運行時顯示阻塞模態對話框和進度條,並在任務完成後隱藏它。

另一種方法是阻塞一段時間,希望任務能夠快速完成,然後備份到異步的方式。這可以使用get method taking a timeout作爲參數來完成。

+2

我認爲這解決了我的問題:目前我所有的方法都使用'SwingWorker's - 這似乎是一個問題,因爲我必須等待結果。我將從這些方法中刪除'SwingWorker'並且只調用一次,但同步執行'SwingWorker'內的所有內容。 – riwi

4

您可以使用異步範例。查看Observer/Observable並使用該作業將結果傳回到當前正在進行輪詢的對象。

+0

我想避免它,因爲它會使我的代碼非常複雜。我有幾個短文件菜單操作(文件 - >打開,新建,關閉,保存,另存爲,退出),依靠對方(即當試圖退出,退出調用關閉,關閉可能會調用保存,保存可能會調用保存如)。 – riwi

+1

夠公平的,它確實增加了複雜性,如果你打算連鎖這樣的運作,它可能不是理想的。 – mcfinnigan

4

使用worker.get()直接是行不通的,因爲它會阻止EDT,等待完成的任務 - 這意味着即使我從SwingWorker中打開對話框不會得到畫。

它們也不與當前代碼一起使用。您忙於等待阻止EDT與調用worker.get()一樣多 - 只有一個事件分派線程,並且SwingWorker中的對話框與該線程在循環中旋轉或等待鎖定一樣被阻止。這裏的問題是,如果一個方法運行在EDT上,它就不能從一個異步操作中返回一個值(不會佔用EDT)給它的調用者。

對完成的異步處理作出反應的正確方法是覆蓋SwingWorker中的done()方法。

也可以查看http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html瞭解更多信息。

4

上面幾位人員提到的一種方法是重寫SwingWorker完成的方法。但是,如果由於某種原因,您希望將SwingWorker代碼發佈到SwingWorker外部和調用代碼之外,則可以利用SwingWorker的屬性更改支持。只需將一個PropertyChangeListener添加到SwingWorker中,並監聽屬性名稱爲「state」的state屬性。然後可以使用getState()方法提取SwingWorker的狀態。完成後,它將返回SwingWorker.StateValue枚舉的DONE值。例如(從答案我在another thread給這裏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(); 
    } 
    } 
0

我遇到了類似的問題,當我想要一個函數返回,將在揮杆工人來計算的值。我不想簡單地通過這個線程來阻止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; 
    } 
} 

我想這不是所有情況下的理想選擇。但我認爲這是一種替代方法,對我來說非常有用。