天天看點

進階多線程控制類

在java1.5中提供了一個非常實用的多線程控制包 java.util. concurrent包,提供了很多可以幫助開發者高效、易維護、結構清晰的Java多線程程式。

         1.ThreadLocal類

用處:儲存線程的獨立變量。當一個線程類在使用ThreadLocal維護變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,是以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。常用于使用者登入控制,如記錄session資訊。

實作:每個Thread都持有一個TreadLocalMap類型的變量(該類是一個輕量級的Map,功能與map一樣,差別是桶裡放的是entry而不是entry的連結清單。功能還是一個map。)以本身為key,以目标為value。

主要方法是get()和set(), ThreadLocal是一個特殊的容器。

        2.原子類(AtomicInteger、AtomicBoolean……)

如果使用atomicInteger,或者使用自己保證原子的操作,則等同于synchronized

//傳回值為boolean

AtomicInteger.compareAndSet(intexpect,int update)

該方法可用于實作樂觀鎖。

       3.Lock類 

lock: 在java.util.concurrent包内。共有三個實作:

ReentrantLock

ReentrantReadWriteLock.ReadLock

ReentrantReadWriteLock.WriteLock

主要目的是和synchronized一樣, 兩者都是為了解決同步問題,處理資源争端而産生的技術。功能類似但有一些差別。

差別如下:

lock更靈活,可以自由定義多把鎖的枷鎖解鎖順序(synchronized要按照先加的後解順序)

提供多種加鎖方案,lock 阻塞式, trylock 無阻塞式, lockInterruptily 可打斷式,還有trylock的帶逾時時間版本。

ReentrantLock    

可重入的意義在于持有鎖的線程可以繼續持有,并且要釋放對等的次數後才真正釋放該鎖。

         使用方法是:

1.先new一個執行個體

static ReentrantLock r=newReentrantLock();

2.加鎖      

r.lock()或r.lockInterruptibly();

此處也是個不同,後者可被打斷。當a線程lock後,b線程阻塞,此時如果是lockInterruptibly,那麼在調用b.interrupt()之後,b線程退出阻塞,并放棄對資源的争搶,進入catch塊。(如果使用後者,必須throw interruptableexception 或catch)    

3.釋放鎖   

r.unlock()

必須做!何為必須做呢,要放在finally裡面。以防止異常跳出了正常流程,導緻災難。這裡補充一個小知識點,finally是可以信任的:經過測試,哪怕是發生了OutofMemoryError,finally塊中的語句執行也能夠得到保證。

ReentrantReadWriteLock

可重入讀寫鎖(讀寫鎖的一個實作) 

 ReentrantReadWriteLock lock = newReentrantReadWriteLock()

  ReadLock r = lock.readLock();

  WriteLock w = lock.writeLock();

兩者都有lock,unlock方法。寫寫,寫讀互斥;讀讀不互斥。可以實作并發讀的高效線程安全代碼

4.容器類

BlockingQueue

ConcurrentHashMap

BlockingQueue

阻塞隊列。該類是java.util.concurrent包下的重要類,通過對Queue的學習可以得知,這個queue是單向隊列,可以在隊列頭添加元素和在隊尾删除或取出元素。類似于一個管  道,特别适用于先進先出政策的一些應用場景。普通的queue接口主要實作有PriorityQueue(優先隊列),有興趣可以研究

BlockingQueue在隊列的基礎上添加了多線程協作的功能:

BlockingQueue

除了傳統的queue功能(表格左邊的兩列)之外,還提供了阻塞接口put和take,帶逾時功能的阻塞接口offer和poll。put會在隊列滿的時候阻塞,直到有空間時被喚醒;take在隊 列空的時候阻塞,直到有東西拿的時候才被喚醒。用于生産者-消費者模型尤其好用,堪稱神器。

常見的阻塞隊列有:

ArrayListBlockingQueue

LinkedListBlockingQueue

DelayQueue

SynchronousQueue

ConcurrentHashMap

高效的線程安全哈希map。請對比hashTable ,concurrentHashMap, HashMap

5.管理類

管理類的概念比較泛,用于管理線程,本身不是多線程的,但提供了一些機制來利用上述的工具做一些封裝。

了解到的值得一提的管理類:ThreadPoolExecutor和 JMX架構下的系統級管理類 ThreadMXBean

ThreadPoolExecutor

如果不了解這個類,應該了解前面提到的ExecutorService,開一個自己的線程池非常友善:

ExecutorService e =Executors.newCachedThreadPool();

   ExecutorService e = Executors.newSingleThreadExecutor();

   ExecutorService e = Executors.newFixedThreadPool(3);

    //第一種是可變大小線程池,按照任務數來配置設定線程,

    //第二種是單線程池,相當于FixedThreadPool(1)

    //第三種是固定大小線程池。

    //然後運作

   e.execute(new MyRunnableImpl());

該類内部是通過ThreadPoolExecutor實作的,掌握該類有助于了解線程池的管理,本質上,他們都是ThreadPoolExecutor類的各種實作版本

corePoolSize:池内線程初始值與最小值,就算是空閑狀态,也會保持該數量線程。

maximumPoolSize:線程最大值,線程的增長始終不會超過該值。

keepAliveTime:當池内線程數高于corePoolSize時,經過多少時間多餘的空閑線程才會被回收。回收前處于wait狀态

unit:

時間機關,可以使用TimeUnit的執行個體,如TimeUnit.MILLISECONDS 

workQueue:待入任務(Runnable)的等待場所,該參數主要影響排程政策,如公平與否,是否産生餓死(starving)

threadFactory:線程工廠類,有預設實作,如果有自定義的需要則需要自己實作ThreadFactory接口并作為參數傳入。

以上就是多線程一些進階控制類的實作,下篇部落格分析多線程實作的并發