在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接口并作為參數傳入。
以上就是多線程一些進階控制類的實作,下篇部落格分析多線程實作的并發