1. 程式人生 > >ExecutorService.shutdown()應該是線上程執行完畢後,才會去關閉

ExecutorService.shutdown()應該是線上程執行完畢後,才會去關閉

ExecutorService.shutdown()應該是線上程執行完畢後,才會去關閉。 
但是我用了計數訊號量Semaphore後,發現執行緒還沒有跑完,他就執行了shutdown(). 


Java程式碼   收藏程式碼
  1. import java.util.concurrent.ExecutorService;  
  2. import java.util.concurrent.Executors;  
  3. import
     java.util.concurrent.Semaphore;  
  4.   
  5. public class SemaphoreTest extends Thread {  
  6.     Semaphore position;  
  7.     private int id;  
  8.   
  9.     public
     SemaphoreTest(int i, Semaphore s) {  
  10.         this.id = i;  
  11.         this.position = s;  
  12.     }  
  13.   
  14.     public void run() {  
  15.         try {  
  16.             if (position.availablePermits() > 0) {  
  17.                 System.out.println("顧客[" + id + "]進入廁所,有空位");  
  18.             } else {  
  19.                 System.out.println("顧客[" + id + "]進入廁所,沒空位,排隊");  
  20.             }  
  21.             position.acquire();  
  22.             System.out.println("【" + id + "】acquire坑位");  
  23.             Thread.sleep((int) (Math.random() * 1000));  
  24.             System.out.println("【" + id + "】完畢release");  
  25.             position.release();  
  26.         } catch (Exception e) {  
  27.             e.printStackTrace();  
  28.         }  
  29.     }  
  30.   
  31.     public static void main(String args[]) {  
  32.         ExecutorService pool = Executors.newCachedThreadPool();  
  33.         Semaphore position = new Semaphore(2); // 初始化兩個空位  
  34.         for (int i = 0; i < 5; i++) {  
  35.             pool.submit(new SemaphoreTest(i, position));  
  36.         }  
  37.         System.out.println("開始釋放執行緒池資源");  
  38.         pool.shutdown();  
  39.         System.out.println("完成釋放執行緒池資源");  
  40.         position.acquireUninterruptibly(2);  
  41.         System.out.println("如廁完畢,清理廁所");  
  42.         position.release(2);  
  43.     }  
  44. }  


PS: 
1、程式碼中主執行緒並沒有等待執行緒池執行完畢這一說,而是持續往下執行 
2、至於訊號量,只會在幾個子執行緒之間發揮作用 
3、主執行緒和執行緒池之間沒有直接關係,執行緒池使用自己的執行緒。生命週期也相互獨立。 
4、shutdown()可以理解為:主執行緒要求執行緒池關閉,但不會為此等待執行緒池執行完畢。 
5、實際發揮了等待作用的並不是執行緒池所提供的能力(當然執行緒池也確實提供了這類能力),而是:position.acquireUninterruptibly(2) 這句話。 
shutdown() 作為函式,當然是立即執行,也即是不再接受新任務了;但是它即不會強行終止正在執行的任務,也不會取消已經提交的任務。也就是說之前提交的5個任務,仍然會執行完畢,且跟主執行緒生命週期無關,也就是即便你直接在後面寫上: if (1==1) return; 來立即結束主函式,你也會發現執行緒池的5個任務會順利執行完畢。 
6、另一個長得很像的函式是: 
shutdownNow(),這個函式比shutdown()更狠,兩點: 
1)、對於尚未執行的任務,全部取消掉; 
2)、對於正在執行的任務,發出interrupt()。 
不過程式因為在發生異常時沒有正確釋放訊號量(應該放在finally塊中釋放),所以如果改為shutdownNow()會出問題:主執行緒死等。 


Java5 併發學習  
ExecutorService中submit和execute的區別  
Java程式碼   收藏程式碼
  1. public List<DrugDpInfoVO> selectRecipeSumVO(final AlertMessageKeyword query, PageBreaker page, final Integer engineRunFlag) {  
  2.     List<DrugDpInfoVO> list = optAlertmessageStatisticMapper.selectRecipeSumVO(this.getBaseDBName(), query, page, engineRunFlag);  
  3.   
  4.     if (null == list || list.isEmpty()) {  
  5.         log.warn("無匹配記錄");  
  6.         return list;  
  7.     }  
  8.   
  9.     //ExecutorService EXECUTORSERVICE = Executors.newFixedThreadPool(50);  
  10.     List<Future<DrugDpInfoVO>> listFuture = new ArrayList<>();  
  11.   
  12.     try {  
  13.         for (final DrugDpInfoVO e : list) {  
  14.             Future<DrugDpInfoVO> future = EXECUTORSERVICE.submit(new Callable<DrugDpInfoVO>() {  
  15.   
  16.                 @Override  
  17.                 public DrugDpInfoVO call() throws Exception {  
  18.   
  19.                     DrugDpInfoVO drugDpInfoVO = optAlertmessageStatisticMapper.selectSingleRecipeSumVO(getBaseDBName(), query, e, engineRunFlag);  
  20.                     drugDpInfoVO.setAmount(e.getAmount());  
  21.                     return drugDpInfoVO;  
  22.   
  23.                 }  
  24.             });  
  25.   
  26.             listFuture.add(future);  
  27.         }  
  28.   
  29.         list.clear();  
  30.   
  31.         for (Future<DrugDpInfoVO> future : listFuture) {  
  32.             list.add(future.get());  
  33.         }  
  34.   
  35.     } catch (Exception e) {  
  36.         log.error(e.getMessage(), e);  
  37.     }  
  38.   
  39.     return list;  
  40. }