2009-06-17 97 views
1

我正在使用一個線程池大小爲1的ThreadPoolExecutor來順序執行swing工作。我遇到了一個特殊情況,一個事件到達時創建一個執行某些客戶端 - 服務器通信的swing工作人員,然後更新ui(在done()方法中)。使用ThreadPoolExecutor的SwingWorker取消

當用戶觸發(點擊某個項目)某些事件時,這種方式可以正常工作,但如果發生很多事件,則不會發生這種情況。但是,這發生,所以我需要取消所有當前運行和計劃的工人。問題是支持ThreadPoolExecutor的隊列沒有意識到SwingWorker的取消過程(至少看起來像這樣)。如此計劃的工人會被取消,但已經在運行的工人不會。

,所以我說<T extends SwingWorker>類型的併發隊列,只要它們不取消,當一個新的事件到達它調用.cancel(真)在隊列中的所有SwingWorkers持有所有工人的參考,並提交新SwingWorker到ThreadPoolExecutor。

摘要:SwingWorkers是使用單個線程在ThreadPoolExecutor中創建和執行的。只有最後提交的工人應該正在運行。

有沒有其他解決方案可以解決這個問題,還是可以這樣做嗎?

只是好奇...

+0

它工作嗎?如果它沒有損壞不修復它(或修復它,直到它,大聲笑) – Gandalf 2009-06-17 16:57:12

+0

是的,它的工作原理。但是編寫併發代碼很困難。我只想知道我的任務是否存在任何概念。 – MrWhite 2009-06-17 20:39:39

回答

2

一種創建單線程的方法ThreadPoolExecutor只執行最後一次傳入的Runnable,是爲了創建一個合適的隊列類並覆蓋所有添加方法以在添加新的可運行隊列之前清除隊列。然後將該隊列設置爲ThreadPoolExecutor的工作隊列。

0

爲什麼你需要一個的ThreadPoolExecutor做這種工作?

你有多少種不同的SwingWorkers來源?因爲如果源只是一個,你應該使用不同的方法。

例如,您可以定義一個類來處理一種工作線程,並將其鏈接到一種類型的項目上,用戶可以在該類項目上觸發操作並關注該類內部的事實,即線程的單個實例應該是運行(例如使用完成任務時清除的單例實例)

+0

我需要一個帶有單線程的線程池執行程序來確保一次只能運行一個任務。但他們中的很多人都沒有,所以我必須排隊。 – MrWhite 2009-06-22 10:12:34

0

而不是使用SwingWorker,您不能使用ThreadPoolExecutor執行客戶端 - 服務器通信,然後調用SwingUtilities.invokeLater以更新UI結果?這對我來說似乎有點乾淨,並且可以確保仍然按順序處理事件和UI更新。

當您向執行者提交任務時,您可以保留對其Future實例的引用,以便您可以根據需要取消該任務。

+0

問題是,我可以從執行程序獲得的未來不會像擺動工作人員那樣提供取消可能性,因爲它只是包裝可運行接口。 – MrWhite 2009-06-22 10:11:48

0

讓我看看我是否正確理解問題。您有一個任務的FIFO隊列,只有最早的一個正在運行。每個任務都需要在UI完成時更新。但是,如果某個用戶事件進入,則需要取消所有任務 - 即需要取消正在運行的任務,並且尚未運行的任務需要從隊列中移除。是對的嗎?

假設是這樣,我不會使用SwingWorker,因爲您只需要一個工作線程,而不是每個任務一個。 FutureTask應該足夠了(假設您覆蓋done()SwingUtilities.invokeLater()進行必要的調用並執行UI更新)。

如果您取消FutureTask,那麼即使其run()方法被調用,它也不會執行任何操作。因此,您可以將FutureTask安全地提交給ExecutorService,因爲知道即使執行者嘗試運行它們,取消也會起作用。

我懷疑一個足夠好的解決辦法只是讓所有FutureTasks可能需要取消的名單,並取消所有當用戶事件用武之地。ExecutorService仍然會嘗試運行它們,但它基本上是沒有任何操作。您需要確保已完成的任務已從列表中刪除,並且您需要確保列表已更新並以線程安全的方式使用(可能來自將任務放在ExecutorService上的同一線程),但這不應該太難了。

我在短短一個小時內就把代碼弄糟了,我不打賭它是正確的,但你明白了。 :)

/** Untested code! Use at own risk. */ 
public class SwingTaskExecutor { 

    // //////////////////////////////////////////////////////////// 
    // Fields 

    private final ExecutorService execSvc = Executors.newFixedThreadPool(1); 

    private final Lock listLock = new ReentrantLock(); 
    private final List<ManagedSwingTask<?>> activeTasks = 
      new ArrayList<ManagedSwingTask<?>>(); 

    // //////////////////////////////////////////////////////////// 
    // Public methods 

    public <T> Future<T> submit(SwingTask<T> task) { 
     ManagedSwingTask<T> managedTask = new ManagedSwingTask<T>(task); 
     addToActiveTasks(managedTask); 
     execSvc.submit(managedTask); 
     return managedTask; 
    } 

    public void cancelAllTasks() { 
     listLock.lock(); 
     try { 
      for (ManagedSwingTask<?> t: activeTasks) { 
       t.cancel(true); 
      } 
      activeTasks.clear(); 
     } finally { 
      listLock.unlock(); 
     } 
    } 

    // //////////////////////////////////////////////////////////// 
    // Private methods 

    private <T> void addToActiveTasks(ManagedSwingTask<T> managedTask) { 
     listLock.lock(); 
     try { 
      activeTasks.add(managedTask); 
     } finally { 
      listLock.unlock(); 
     } 
    } 

    // //////////////////////////////////////////////////////////// 
    // Helper classes 

    private class ManagedSwingTask<T> extends FutureTask<T> { 

     private final SwingTask<T> task; 

     ManagedSwingTask(SwingTask<T> task) { 
      super(task); 
      this.task = task; 
     } 

     @Override 
     public void cancel(boolean mayInterruptIfRunning) { 
      try { 
       task.cancel(); 
      } finally { 
       super.cancel(mayInterruptIfRunning); 
      } 
     } 

     @Override 
     protected void done() { 
      removeFromActiveTasks(); 
      updateUIIfDone(); 
     } 

     private void removeFromActiveTasks() { 
      listLock.lock(); 
      try { 
       activeTasks.remove(this); 
      } finally { 
       listLock.unlock(); 
      } 
     } 

     private void updateUIIfDone() { 
      if (isDone()) { 
       SwingUtilities.invokeLater(new Runnable() { 
        @Override 
        public void run() { 
         task.updateUI(); 
        } 
       }); 
      } 
     } 
    } 

    public static interface SwingTask<T> extends Callable<T> { 

     /** Called from the EDT if task completes successfully */ 
     void updateUI(); 

     /** Hook in case there's task-specific cancellation to be done*/ 
     void cancel(); 
    } 
} 

這樣的事情,無論如何。

如果您想雙倍肯定,可以關閉並更換ExecutorService,但這可能不是必需的。

相關問題