2014-02-26 70 views
2

我在ThreadPoolExecutor中運行任務時發現了一個意外的死鎖。Executor中的意外死鎖

這個想法是啓動改變標誌的輔助任務的主要任務。 主任務暫停,直到輔助任務更新標誌。

  • 如果corePoolSize> = 2,則主任務按預期完成。
  • 如果corePoolSize < 2似乎是次要任務是enquenqued但從未啓動。
  • 改爲使用SynchronousQueue,即使對於corePoolSize = 0,主任務也會完成。

我想知道:

  • 什麼是死鎖的原因?從 文檔看來似乎不明顯。
  • 爲什麼使用SynchronousQueue代替LinkedBlockingQueue可防止死鎖?
  • 是corePoolSize = 2一個安全的值來防止這種死鎖?

    import java.util.concurrent.*; 
    class ExecutorDeadlock { 
        /*------ FIELDS -------------*/ 
        boolean halted = true; 
        ExecutorService executor; 
        Runnable secondaryTask = new Runnable() { 
         public void run() { 
          System.out.println("secondaryTask started"); 
          halted = false; 
          System.out.println("secondaryTask completed"); 
          } 
        }; 
        Runnable primaryTask = new Runnable() { 
         public void run() { 
         System.out.println("primaryTask started"); 
         executor.execute(secondaryTask); 
         while (halted) { 
          try { 
           Thread.sleep(500); 
          } 
          catch (Throwable e) { 
           e.printStackTrace(); 
          } 
         } 
         System.out.println("primaryTask completed"); 
         } 
        }; 
    
        /*-------- EXECUTE -----------*/ 
        void execute(){ 
         executor.execute(primaryTask); 
        } 
    
        /*-------- CTOR -----------*/ 
        ExecutorDeadlock(int corePoolSize,BlockingQueue<Runnable> workQueue) { 
         this.executor = new ThreadPoolExecutor(corePoolSize, 4,0L, TimeUnit.MILLISECONDS, workQueue); 
        } 
    
        /*-------- TEST -----------*/ 
        public static void main(String[] args) { 
         new ExecutorDeadlock(2,new LinkedBlockingQueue<>()).execute(); 
         //new ExecutorDeadlock(1,new LinkedBlockingQueue<>()).execute(); 
         //new ExecutorDeadlock(0,new SynchronousQueue<>()).execute(); 
        } 
    } 
    

回答

7

你怎麼能指望這個工作的線程數< 2如果

  • 你只有1個執行線程
  • 第一TAST添加次要任務的執行隊列中,等待爲它啓動

任務是由執行程序服務從隊列中提取時在游泳池裏是免費的執行者。在你的情況下(< 2)執行程序線程永遠不會被第一個任務釋放。 這裏沒有死鎖問題。

編輯:

好吧,我心中已經挖出了一些信息,這就是我發現。首先從ThreadPoolExecutor

任何BlockingQueue可用於傳輸和保存提交的任務。 使用這種隊列的與池大小進行交互:

If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing. 
If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread. 
If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected. 

好,現在作爲用於queuess offer方法

SyncQueue:

將指定元素插入此隊列中,如果另一線程是 等待接收它。

的LinkedBlockingQueue

將指定元素插入此隊列中,如果有必要等待空間變得可用。 offer方法

返回值決定whetever新的任務將被排隊或在新的線程運行。

因爲LinkedBlockingQueue排隊新任務,因爲它可以有足夠的容量,任務被排隊並且沒有新線程產生。但SyncQueu不會排隊另一個任務,因爲沒有其他線程正在等待某些東西被入隊(offer返回false,因爲任務未入隊),這就是爲什麼會產生新的執行程序線程。

如果您閱讀javadocs爲ThreadPoolExecutorLinkedBlockingQueueSynchronousQueue +檢查execute方法的實現,您會得到相同的結論。

所以你錯了,在文檔中有explenation :)

+0

你的意思是corePoolSize包括任務來管理隊列? – plastilino

+0

它指定執行程序線程數 – Antoniossss

+0

對不起,我無法得到它。最多允許4個線程共存。並且還有SyncQueue情況... – plastilino