synchronized的功能擴展:
重入鎖;ReentrantLock;
其實也就是lock對於synchronized的替代了,要注意的一個點就是你可以鎖多個,但是你鎖了幾個,最后就要解鎖幾個這個問題;
使用lock.lock()加鎖,使用lock.unlock()解鎖;
提供中斷處理;
使用中斷鎖,線程可以被中斷,也就是說,當一個線程正在等待鎖的時候,他依然可以收到一個通知,被告知無須等待,可以停止工作了,使用的是lock.lockInterruptibly();方法;
鎖申請等待限時;
給鎖給定一個時間,如果超過了這個時間的話,就讓線程自動放棄;使用的是lock.trylock(時間段,時間單位);另外還有一個就是lock.trylock();如果是帶參數的,就是最多等待這么多時間,超過了時間就返回false,成功獲得了鎖,就返回true;如果是不帶參數直接運行,就是比較直接的,如果鎖未被占用,則申請鎖成功,返回true,否則就是失敗了,直接返回false;
公平鎖;
公平鎖的一個特點就是:它不會產生飢餓現象;所有的鎖都是先到先等,不得插隊;但是維持公平需要一個有序隊列,實現成本較高,性能相對也非常低下,默認情況下,鎖是非公平的;
以下是我們整理的幾個重要方法:
1,lock():獲得鎖,如果鎖已經被占用,則等待;
2,lockInterruptibly():獲得鎖,但優先響應中斷;
3,tryLock():嘗試獲得鎖,如果成功,返回true,失敗返回false,該方法不等待,立即返回;
4,tryLock(Long time,TimeUnit unit):在給定的時間內嘗試獲得鎖;
5,unlock():釋放鎖;
重入鎖的好搭檔:Condition條件;
使用new Condition可以生成與當前重入鎖綁定的Condition實例;使得我們可以讓線程在合適的時間等待,或者在某一特定的時刻得到通知,繼續執行;
1,await();讓當前線程等待,同時釋放當前鎖,作用上和wait()相似;
2,awaitUninterruptibly();與await()方法基本相同,不會在等待過程中響應中斷;
3,singal();用於喚醒一個在等待中的線程,相對的singalAll()方法會喚醒所有在等待中的線程,和notify()類似;
允許多個線程同時訪問:信號量;
只允許一個線程訪問一個資源,而信號量則可以指定多個線程;
public Semaphore(int permits)
public Semaphore(int permits,boolean fair);第二個參數可以指定是否公平鎖;
這所謂的信號量,其實就是一個執行器啦,只是換了名字看不出來了而已。。。參數可以指定有多少個線程;
ReadWriteLock讀寫鎖;
關於讀寫的問題,我們要明確的一點就是,我們可以對一個文件多次重復讀取,但是當讀與寫發生沖突的時候,我們要做的就是保證他們的互斥了;
讀讀不互斥;
讀寫互斥;
寫寫互斥;
如果讀的操作遠遠大於寫的操作的話,讀寫鎖就會發揮最大的功效;
Lock readLock = readWriteLock.readLock();
Lock writeLock = readWriteLock.writeLock();
讀線程完全並行,而寫會阻塞讀;
倒計時器:CountDownLatch;
此工具通常用來控制線程等待,讓某一個線程等待知道倒計時結束,再開始執行;
只有當你一開始設定的所有線程都跑完了,你這個倒計時器才算真正結束了;
CountDownLatch end = new CountDownLatch(10);
end.countDown();
當調用CountDownLatch.countDown()方法的時候,也就是通知CountDownLatch,一個線程已經完成了任務,倒計時器可以減1了;
循環珊欄;CyclicBarrier;
另外一種多線程並發控制實用工具;
其實本質上跟倒計時器是差不多的功能類似,唯一的區別就在於可以反復使用,而且可以設置,當計數結束之后,系統下一步要執行的動作;
public CyclicBarrier(int parties,Runnable barrierAction);
其中barrierAction是執行的動作;
線程阻塞工具類:LockSupport;
可以在線程內任意位置讓線程阻塞;和Thread.suspend()相比,彌補了由於resume()在前發生,導致線程無法繼續執行的情況;
與object.wait()相比,不需要先獲得某個對象的鎖,也不會拋出interruptedException異常;
LockSupport.park();
LockSupport.unpark(t1);
除了有定時阻塞的功能外,LockSupport.park()還能支持中斷影響;但是LockSuppor.park()不會拋出InterruptedException異常,他只是默默的返回;
也就是說:LockSupport.park()進行阻塞之后,如果中斷這個線程,不會拋出異常,而是默默的返回;
線程復用:線程池;
我們在這里用到了池的概念來保存管理我們的線程;
當我們要使用線程的時候,不是創建,而是從池子中去取,當我們要關閉線程的時候,是將這個線程返回給池子,方便其他人使用;
JDK對線程池的支持;
newFixedThreadPool(int nThreads);
newSingleThreadExecutor();
newCachedThreadTool();
newSingleThreadScheduledExector();
newScheduledThreadPool(int corePoolSize);
newFixedThreadPool():該方法返回一個固定線程數量的線程池;線程池的數量保持不變,若線程池已滿,新的任務會被暫存在一個任務隊列中;
newSingleThreadExecutor();該線程池只有一個線程在里面,多余任務會被保存到一個任務隊列中;
newCachedThreadPool();返回一個根據實際情況調整線程數量的線程池,也就是說,這個線程池中的線程是可以可調整的。當所有的線程都在工作而此時又有新的任務提交,則會擴展線程的數量;
newSingleThreadScheduledExecutor();返回一個ScheduledExecutorService對象,在ExecutorService接口上擴展了在給定時間執行某任務的功能,
newScheduledThreadPool()方法,可以指定線程數量和時間的線程池;
核心線程池的內部實現;
都是在原有的ThreadPoolExecutor()的基礎上進行的參數設置和修改;
而其實,這個ThreadPoolExecutor()內部的參數也有很多的;
int corePoolSize;線程池中線程的數量;
int maximumPoolSize;指定了線程池的最大線程數量;
long keepAliveTime;當線程池數量超過了corePoolSize時嗎,多與的空閑線程的存活時間;
TimeUnit unit;keepAliveTime的時間單位;
BlockingQueue<Runnable> workQueue:任務隊列,被提交但尚未被執行的任務;
ThreadFactory threadFactory;線程工廠,用於創建線程,一般用默認的;
handler;拒絕策略,當任務太多來不及處理,如何拒絕任務;
現在我們上面的幾個線程池是如何通過ThreadPoolExecutor()以及內部的參數來設定的呢,我們現在就來說一下;
其中newFixedThreadPool(nThreads,nThreads,0L,new LinkedBlockingQueue<Runnable>);
newSingleThreadExecutor(1,1,0L,new LinkedBlockingQueue<Runnable>);
newCachedThreadPool(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
其中,我們可以看出,當newCachedThreadPool時,我們是指定線程池數量為0,但是最大線程數為無限,而且采用的任務隊列跟上面的隊列不一樣,下面將重點說明這兩種任務隊列的不同之處;
SynchronousQueue:這是直接提交的隊列,每一個線程都會直接提交,不會真實地保存,而是直接將新任務交給線程執行器;
ArrayBlockingQueue:這是有界的任務隊列,需要帶一個參數,表示該隊列的最大容量;
LinkedBlockingQueue:這是無界的任務隊列,多余的任務會先放到這里;
PriorityBlockingQueue:這是優先任務隊列,根據任務自身的優先級順序先后執行;
不要重復發明輪子:JDK的並發容器;
ConcurrentHashMap:高效的並發HashMap;
CopyOnWriteArrayList:在讀多寫少的場合,這個List的性能非常好,遠遠好於Vector(另外。。Vector已經過時了,不用了);
ConcurrentLinkedQueue:高效的並發隊列,使用鏈表實現,可以看做一個線程安全的LinkedList;
BlockingQueue:表示阻塞隊列,詳情可以查看一下生產者——消費者模式;
ConcurrentSkipListMap:跳表的實現;這是一個Map,使用跳表的數據結構進行快速查找;
以上並發容器的內部數據結構實現,我們在下一章會提到;敬請期待!