JavaThread多執行緒執行緒池

嗯哼9925發表於2017-11-08

執行緒池

執行緒相關類、集合

16、執行緒池
    Why? 系統啟動一個新執行緒的成本比較高,因為涉及到與作業系統互動。這個時候用執行緒池可以很好的提高效能,
    尤其是當程式中需要建立大量生存期很短暫的執行緒時,更應該考慮使用執行緒池。
    原理:(流程)執行緒池和資料庫連線池有點類似的是,執行緒池在系統啟動時建立大量空閒執行緒,程式將一個Runnable物件傳給執行緒池,
    執行緒池就會啟動一條執行緒來執行該執行緒物件的run方法,當run方法執行結束後,該執行緒並不會死亡,而是再次返回執行緒池中成為空閒執行緒,
    等待執行下一個Runnable物件的run方法。
 
    優點:使用執行緒池可以有效的控制系統中併發執行緒的數量,當系統中包含大量的併發執行緒時,會導致系統效能劇烈下降,
    甚至導致JVM的崩潰,而執行緒池的最大執行緒引數可以控制系統中併發執行緒數目不超過此數目。
 
    在JDK1.5開始,提供Java內建的執行緒池,JDK提供一個Executors工廠類來產生執行緒池,該工程類包含如下幾個靜態工廠方法來建立連線池:
    A、newCachedThreadPool():建立一個具有快取功能的執行緒池,系統根據需要建立執行緒,這些執行緒將會被快取線上程池中。
    B、newFixedThreadPool(int nThreads):建立一個可重用的、具有固定執行緒數的執行緒池
    C、newSingleThreadExecutor():建立一個只有單執行緒的執行緒池,它相當於newFixedThreadPool方法傳遞引數1
    D、newScheduledThreadPool(int corePoolSize):建立具有指定執行緒數的執行緒池,它可以在指定延遲後執行執行緒任務,
        corePoolSize 指池中所保持的執行緒數,即使執行緒是空閒的也被儲存線上程池內。
    E、newSingleThreadScheduiedExecutor():建立只有一條執行緒的執行緒池,它可以在指定延時後執行執行緒任務。
    以上5個方法的前三個方法返回的是一個ExecutorService物件,該物件代表一個執行緒池,它可以執行Runnable物件或Callable物件所代表的執行緒。
    而後兩個方法返回一個ScheduledExecutorService執行緒池,它是ExecutorService的子類,它可以在指定延時後執行執行緒任務。
 
    ExecutorService代表儘快執行執行緒的執行緒池(只要執行緒中有空閒的執行緒就立即執行執行緒任務)。
    程式只要將一個Runnable物件或Callable物件(代表執行緒任務)提及給該執行緒池即可,該執行緒池就會盡快的執行任務。
    ExecutorService裡提供如下3個方法:
    A、Future<?> submit(Runnable task):將一個Runnable物件提交給指定的執行緒池。執行緒池將在有空閒執行緒時執行Runnable物件的代表的任務。
        其中Future物件代表Runnable任務的返回值—run方法蠻腰返回值,所以Future物件將在run方法執行結束後返回null,
        但可以呼叫Future的isDone,isCancelled方法來獲得Runnable物件的執行狀態
    B、<T> Future<T> submit(Runnable task, T reslut):將一個Runnable物件提及給指定的執行緒池,執行緒池將在有空閒執行緒時執行Runnable物件代表的任務,
        result顯示執行執行緒執行結束後的返回值,所以Future物件將在run方法執行結束後返回result
    C、<T> Future<T> submit(Callable<T> task):將一個Callable物件提交給指定執行緒池。執行緒池將在有空閒執行緒時執行Callable物件代表的任務,
        Future代表Callable物件裡的call方法的返回值
    
    ScheduledExecutorService代表可在指定延遲或週期性執行執行緒任務的執行緒池,它提供瞭如下方法:    
    A、ScheduledFuture<V> schedule(Callable<V> callable, long delay, Timeout unit):指定Callable任務將在delay延遲後執行
    B、ScheduledFuture<V> schedule(Runnable command, long delay, Timeout unit):指定command任務將在delay延遲後執行
    C、ScheduleFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
        指定command任務將在delay延長後執行,而且以設定頻率重複執行,也就是說,在initialDelay後開始執行,
        異常在initialDelay+2* period 處重複執行,依次類推
    D、ScheduleFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, Timeout unit)
        建立並執行一個在給定初始延遲後首次啟用的定期操作,隨後,在每一次執行終止和下一次執行開始之間都存在給定的延遲。
        如果任務的任一次執行遇到異常,就會取消後續執行。否則,只能通過程式來顯示取消或終止任務
    當用完一個執行緒池後,應該呼叫shutdown方法,該方法將啟動執行緒池的關閉序列,呼叫了shutdown方法後執行緒池不再接受新的任務,
    但會將以前所有一提交的任務執行完成。當執行緒池所有執行緒任務執行完畢後,池中所有執行緒都會死亡。另外也可以執行執行緒池的shutdownNow方法來關閉執行緒池,
    該方法試圖停止所有正在執行的活動任務,暫停處理正在等待的任務,並返回等待執行任務列表。
    使用執行緒池來執行執行緒任務步驟:
    A、呼叫Executors類的靜態工廠方法建立一個ExecutorService物件,該物件代表一個執行緒池
    B、建立Runnable實現類或是Callable實現類的例項,作為執行緒的執行任務
    C、呼叫ExecutorService物件的submit方法來提交Runnable和Callable例項
    D、當不想提交任務時呼叫ExecutorService物件的shutdown方法來關閉執行緒池
 
17、執行緒相關類
    一、ThreadLocal類
        在JDK5後ThreadLocal引入了泛型的支援,通過使用ThreadLocal可以簡化多多執行緒的程式設計時是併發訪問,使用這個工具類可以幫我們更好的實現多執行緒。
        ThreadLocal,是Thread Local Variable(執行緒的區域性變數)的意思。執行緒區域性變數功能非常簡單,就是為每一個使用該變數的執行緒都提供一個變數值的副本,
        是每一個執行緒都可以獨立的改變自己的副本,而不會和其他執行緒的副本衝突。
        ThreadLocal提供常用方法:
            A、T get():返回此執行緒區域性變數中當前執行緒副本中的值
            B、void remove():刪除此執行緒區域性變數中當前執行緒副本中的值
            C、void set(T value):設定此執行緒區域性變數中當前執行緒副本中的值
        ThreadLocal和其他所有同步機制都是為了解決多執行緒中對同一變數的訪問衝突,在普通的同步機制中,是通過物件加鎖來實現多個執行緒對同一變數的安全訪問的。
        在這種情形下,該變數是多個執行緒共享的,所以要使用這種同步機制需要很細緻的分析在什麼時候對變數進行讀寫,
        上面時候需要鎖定某個物件,什麼時候釋放物件鎖等。
        在這種情況下系統並沒有將這份資源複製多份,只是採用了案情機制來控制隊這份資源的訪問而已。
        ThreadLocal就從另一個角度來解決多執行緒的併發訪問,ThreadLocal將需要併發訪問的資源複製出多份,每個執行緒擁有一份資源,每個執行緒都擁有自己的資源副本,
        從而也就沒有必要對該變數進行同步了。ThreadLocal提供了執行緒安全的物件,在編寫多執行緒程式碼時,可以把不安全的整個變數封裝進ThreadLocal,
        或者把該物件與現場相關的狀態使用ThreadLocal儲存。
        ThreadLocal並不能代替同步機制,兩者面向的問題領域不同。同步機制是為了同步多個執行緒對相同資源的併發訪問,是多個執行緒之間進行通訊的有效方式;
        而ThreadLocal是隔離多個執行緒的資料共享,從根本上避免了多個執行緒之間共享資源(變數),也就不需要對多個執行緒進行同步了。
        通常認為:如果需要進行多個執行緒之間的共享資源,已到達執行緒之間的通訊功能,就使用步機制,如果僅僅需要隔離多個執行緒之間的共享衝突,就用ThreadLocal。
    
    二、包裝執行緒不安全集合
        當用多執行緒操作集合時,對執行緒不安全的集合進行操作容易破壞集合資料的完整性。
        A、<T> Collection<T> synchronizedCollection(Collection<T> c):返回指定collection對應的執行緒安全的collection
        B、static <T> List<T> synchronizedList(List<T> list):返回指定List對應的現場安全的List物件
        C、static <K, V> Map<K, V> synchronizedMap(Map<K, V> m):返回指定Map物件對應的現場安全的Map物件
        D、static <T> Set<T> synchronizedSet(Set<T> s):返回指定Set對應的執行緒安全的Set
        E、static <K, V> SortedMap<K, V> synchronizedSortedMap(SortedMap<K, V> m):返回指定SortedMap物件所對應執行緒安全的SortedMap物件
        F、static <K, V> SortedSet<K, V> synchronizedSortedSet(SortedSet<K, V> m):返回指定SortedSet物件所對應執行緒安全的SortedSet 物件
        使用執行緒安全的HashMap物件:
        HashMap map = Collections.synchronizedMap(new HashMap());
        注意:如果需要把某個集合包裝成執行緒安全的集合,則應該在建立之後立即包裝,包裝後就是執行緒安全的HashMap物件了。
 
    三、執行緒安全的集合
        在JDK5後提供了java.util.concurrent包的ConcurrentHashMap、ConcurrentLinkedQueue兩個支援併發訪問的集合,
        它們分別代表了支援併發訪問的HashMap和支援併發訪問的Queue。預設都支援多執行緒併發寫入,寫入操作是執行緒安全的,讀取不必鎖定。
        這兩個集合採用了複雜的演算法,他們是永遠都鎖不住的集合。
        當多執行緒共享訪問一個集合時,ConcurrentLinkedQueue最合適不過,Queue不允許為null元素。
        Quee實現了多執行緒的高效訪問,多條執行緒訪問ConcurrentLinkedQueue集合是無需等待。
        ConcurrentHashMap預設支援16條執行緒併發訪問,當有超過16條執行緒併發訪問就需要等待。
        但可以設定concurrentLevel構造方法引數(預設16)來支援更多的執行緒併發數量。
        與HashMap和普通集合不同的是,當我們用迭代器變數ConcurrentHashMap、ConcurrentLinkedQueue時,
        如果在迭代器建立後對集合元素的修改是不會在迭代器中做出修改,也不會出現異常。
        如果用Collection作為集合物件時,如果物件在建立迭代器後發生變化修改,就會引發ConcurrentModificationException
    
本文轉自hoojo部落格園部落格,原文連結:http://www.cnblogs.com/hoojo/archive/2011/05/05/2038111.html,如需轉載請自行聯絡原作者


相關文章