10.線程和線程池的區別,線程池有哪些,什麼情況下使用

一:線程和線程池的區別

(1)new Thread 的弊端

      a. 每次new Thread時,新建對象性能差。
      b. 線程缺乏統一管理,可能無限制新建線程,相互之間競爭,可能佔用過多系統資源導致死機或oom。
      c. 缺乏更多功能,如定時執行、定期執行、線程中斷。

(2)Java提供的四種線程池相比new Thread的優勢

     a. 重用存在的線程,減少對象創建、消亡的開銷,性能佳。
     b. 可有效控制最大併發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
     c. 提供定時執行、定期執行、單線程、併發數控制等功能。

二:Java線程池有哪些

Java通過Executors提供四種線程池

      newCachedThreadPool      創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。
      newFixedThreadPool          創建一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
      newScheduledThreadPool  創建一個定長線程池,支持定時及週期性任務執行。
      newSingleThreadExecutor  創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

三:什麼場景下使用

(1)newCachedThreadPool:

      底層:返回ThreadPoolExecutor實例,corePoolSize爲0;maximumPoolSize爲Integer.MAX_VALUE;keepAliveTime爲60L;unit爲TimeUnit.SECONDS;workQueue爲SynchronousQueue(同步隊列)

        通俗:當有新任務到來,則插入到SynchronousQueue中,由於SynchronousQueue是同步隊列,因此會在池中尋找可用線程來執行,若有可以線程則執行,若沒有可用線程則創建一個線程來執行該任務;若池中線程空閒時間超過指定大小,則該線程會被銷燬。

        適用:執行很多短期異步的小程序或者負載較輕的服務器

(2)newFixedThreadPool:

        底層:返回ThreadPoolExecutor實例,接收參數爲所設定線程數量nThread,corePoolSize爲nThread,maximumPoolSize爲nThread;keepAliveTime爲0L(不限時);unit爲:TimeUnit.MILLISECONDS;WorkQueue爲:new LinkedBlockingQueue<Runnable>() 無解阻塞隊列

        通俗:創建可容納固定數量線程的池子,每隔線程的存活時間是無限的,當池子滿了就不在添加線程了;如果池中的所有線程均在繁忙狀態,對於新任務會進入阻塞隊列中(無界的阻塞隊列)

        適用:執行長期的任務,性能好很多

(3)newSingleThreadExecutor:

      底層:FinalizableDelegatedExecutorService包裝的ThreadPoolExecutor實例,corePoolSize爲1;maximumPoolSize爲1;keepAliveTime爲0L;unit爲:TimeUnit.MILLISECONDS;workQueue爲:new LinkedBlockingQueue<Runnable>() 無解阻塞隊列

        通俗:創建只有一個線程的線程池,且線程的存活時間是無限的;當該線程正繁忙時,對於新任務會進入阻塞隊列中(無界的阻塞隊列)

        適用:一個任務一個任務執行的場景

(4)NewScheduledThreadPool:

   底層:創建ScheduledThreadPoolExecutor實例,corePoolSize爲傳遞來的參數,maximumPoolSize爲Integer.MAX_VALUE;keepAliveTime爲0;unit爲:TimeUnit.NANOSECONDS;workQueue爲:new DelayedWorkQueue() 一個按超時時間升序排序的隊列

        通俗:創建一個固定大小的線程池,線程池內線程存活時間無限制,線程池可以支持定時及週期性任務執行,如果所有線程均處於繁忙狀態,對於新任務會進入DelayedWorkQueue隊列中,這是一種按照超時時間排序的隊列結構

       適用:週期性執行任務的場景

 

線程池任務執行流程:

        1)當線程池小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閒線程。

        2)當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行

        3)當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務

       4)當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理

       5)當線程池中超過corePoolSize線程,空閒時間達到keepAliveTime時,關閉空閒線程

       6) 當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閒時間達到keepAliveTime也將關閉

       一般如果線程池任務隊列採用LinkedBlockingQueue隊列的話,那麼不會拒絕任何任務(因爲隊列大小沒有限制),這種情況下,ThreadPoolExecutor最多僅會按照最小線程數來創建線程,也就是說線程池大小被忽略了。

       如果線程池任務隊列採用ArrayBlockingQueue隊列的話,那麼ThreadPoolExecutor將會採取一個非常負責的算法,比如假定線程池的最小線程數爲4,最大爲8所用的ArrayBlockingQueue最大爲10。隨着任務到達並被放到隊列中,線程池中最多運行4個線程(即最小線程數)。即使隊列完全填滿,也就是說有10個處於等待狀態的任務,ThreadPoolExecutor也只會利用4個線程。如果隊列已滿,而又有新任務進來,此時纔會啓動一個新線程,這裏不會因爲隊列已滿而拒接該任務,相反會啓動一個新線程。新線程會運行隊列中的第一個任務,爲新來的任務騰出空間。

       這個算法背後的理念是:該池大部分時間僅使用核心線程(4個),即使有適量的任務在隊列中等待運行。這時線程池就可以用作節流閥。如果擠壓的請求變得非常多,這時該池就會嘗試運行更多的線程來清理;這時第二個節流閥—最大線程數就起作用了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章