前言:剛學習了一段機器學習,最近須要重構一個java項目,又趕過來看java。大可能是線程代碼,沒辦法,那時候總以爲多線程是個很難的部分不多用到,因此一直沒下決定去啃,那些年留下的坑,老是得本身跳進去填一次。html
思路:大概看了線程相關的一些知識,對線程的運行機制,同步機制,以及整個系統都作一個全面的瞭解。在深刻每個部分去看一下線程及其相關包的源碼作深刻了解。java
目標:線程,併發包(線程池,併發的數據結構,鎖,原子類)。程序員
經過一些資料的查看最終把目標定位在線程和併發包上,線程是核心,併發包是輔助工具,用於多線程運行時的併發問題。其實這樣看來多線程並無不少的東西,支持併發的數據結構用於保證數據的安全性,各類鎖機制用來保證類,對象,方法,屬性的併發安全。它的難點主要是在運用上,各類鎖機制的運用,會給系統帶來負擔,也會給程序性能帶來影響,可是同時又要保證數據的同步。鎖機制使用的強度和位置,直接決定了併發系統的好壞。web
java中文API:http://www.javaweb.cc/help/JavaAPI1.6/overview-summary.html,下面具體看一下這些包裏面有哪些東西。算法
主要涉及到下面幾個包:數組
線程相關:java.lang下面的幾個類安全
接口摘要 | |
Runnable | Runnable 接口應該由那些打算經過某一線程執行其實例的類來實現。 |
類摘要 |
---|
Thread | 線程 是程序中的執行線程。 |
ThreadGroup | 線程組表示一個線程的集合。 |
ThreadLocal<T> | 該類提供了線程局部 (thread-local) 變量。 |
併發包相關:數據結構
1. Java.util.concurrent包多線程
接口摘要 | |
BlockingDeque<E> | 支持兩個附加操做的 Queue ,這兩個操做是:獲取元素時等待雙端隊列變爲非空;存儲元素時等待雙端隊列中的空間變得可用。 |
BlockingQueue<E> | 支持兩個附加操做的 Queue ,這兩個操做是:獲取元素時等待隊列變爲非空,以及存儲元素時等待空間變得可用。 |
Callable<V> | 返回結果而且可能拋出異常的任務。 |
CompletionService<V> | 將生產新的異步任務與使用已完成任務的結果分離開來的服務。 |
ConcurrentMap<K,V> | 提供其餘原子 putIfAbsent、remove、replace 方法的 Map 。 |
ConcurrentNavigableMap<K,V> | 支持 NavigableMap 操做,且以遞歸方式支持其可導航子映射的 ConcurrentMap 。 |
Delayed | 一種混合風格的接口,用來標記那些應該在給定延遲時間以後執行的對象。 |
Executor | 執行已提交的 Runnable 任務的對象。 |
ExecutorService | Executor 提供了管理終止的方法,以及可爲跟蹤一個或多個異步任務執行情況而生成 Future 的方法。 |
Future<V> | Future 表示異步計算的結果。 |
RejectedExecutionHandler | 沒法由 ThreadPoolExecutor 執行的任務的處理程序。 |
RunnableFuture<V> | 做爲 Runnable 的 Future 。 |
RunnableScheduledFuture<V> | 做爲 Runnable 的 ScheduledFuture 。 |
ScheduledExecutorService | 一個 ExecutorService ,可安排在給定的延遲後運行或按期執行的命令。 |
ScheduledFuture<V> | 一個延遲的、結果可接受的操做,可將其取消。 |
ThreadFactory | 根據須要建立新線程的對象。 |
枚舉摘要 | |
TimeUnit | TimeUnit 表示給定單元粒度的時間段,它提供在這些單元中進行跨單元轉換和執行計時及延遲操做的實用工具方法。 |
2. java.util.concurrent.locks包併發
接口摘要 | |
Condition | Condition 將 Object 監視器方法(wait 、notify 和 notifyAll )分解成大相徑庭的對象,以便經過將這些對象與任意 Lock 實現組合使用,爲每一個對象提供多個等待 set(wait-set)。 |
Lock | Lock 實現提供了比使用 synchronized 方法和語句可得到的更普遍的鎖定操做。 |
ReadWriteLock | ReadWriteLock 維護了一對相關的鎖 ,一個用於只讀操做,另外一個用於寫入操做。 |
類摘要 | |
AbstractOwnableSynchronizer | 能夠由線程以獨佔方式擁有的同步器。 |
AbstractQueuedLongSynchronizer | 以 long 形式維護同步狀態的一個 AbstractQueuedSynchronizer 版本。 |
AbstractQueuedSynchronizer | 爲實現依賴於先進先出 (FIFO) 等待隊列的阻塞鎖和相關同步器(信號量、事件,等等)提供一個框架。 |
LockSupport | 用來建立鎖和其餘同步類的基本線程阻塞原語。 |
ReentrantLock | 一個可重入的互斥鎖 Lock ,它具備與使用 synchronized 方法和語句所訪問的隱式監視器鎖相同的一些基本行爲和語義,但功能更強大。 |
ReentrantReadWriteLock | 支持與 ReentrantLock 相似語義的 ReadWriteLock 實現。 |
ReentrantReadWriteLock.ReadLock | ReentrantReadWriteLock.readLock() 方法返回的鎖。 |
ReentrantReadWriteLock.WriteLock | ReentrantReadWriteLock.writeLock() 方法返回的鎖。 |
3. java.util.conturrent.atomic
類摘要 | |
AtomicBoolean | 能夠用原子方式更新的 boolean 值。 |
AtomicInteger | 能夠用原子方式更新的 int 值。 |
AtomicIntegerArray | 能夠用原子方式更新其元素的 int 數組。 |
AtomicIntegerFieldUpdater<T> | 基於反射的實用工具,能夠對指定類的指定 volatile int 字段進行原子更新。 |
AtomicLong | 能夠用原子方式更新的 long 值。 |
AtomicLongArray | 能夠用原子方式更新其元素的 long 數組。 |
AtomicLongFieldUpdater<T> | 基於反射的實用工具,能夠對指定類的指定 volatile long 字段進行原子更新。 |
AtomicMarkableReference<V> | AtomicMarkableReference 維護帶有標記位的對象引用,能夠原子方式對其進行更新。 |
AtomicReference<V> | 能夠用原子方式更新的對象引用。 |
AtomicReferenceArray<E> | 能夠用原子方式更新其元素的對象引用數組。 |
AtomicReferenceFieldUpdater<T,V> | 基於反射的實用工具,能夠對指定類的指定 volatile 字段進行原子更新。 |
AtomicStampedReference<V> | AtomicStampedReference 維護帶有整數「標誌」的對象引用,能夠用原子方式對其進行更新。 |
對每一個包裏的部分類進行結構解析:
1. Java.util.concurrent:這個包裏,主要經常使用到的是數據結構Queue,MAP,List,和線程池
*&*Queue隊列相關的類圖:
*&*List和Set相關的類圖:List和Set在併發包中的實現類有copyOwriteArrayList,CopyOnWriteArraySet,ConcurrentSkipListSet,三個類
*&*Map相關的類圖:併發包中與Map相關的包括ConcurrentHashMap,ConcurrentSkipListMap兩個類
這些都是和數據結構相關的,其中藍色的部分表示的是併發包的內容,灰色部分表示其餘包(大部分是util)中的內容。其中省略了一部份內容類和接口,由於不少不經常使用,並且用的時候一部分也不是做爲一個數據結構來用的。這也不是這部分關注的重點。咱們主要關注併發包相關的內容。這三張類圖,應該可讓你們對併發包的數據結構有一個大體的瞭解,併發包還有一個內容就是線程池。
*&*線程池類圖:線程池重最終有兩個實現類ThreadPoolExeutor和SheduleThreadPoolExeutor.可是咱們通常不直接去實現這兩個類去建立一個線程池,咱們一般用Exeutors這個類來建立一個線程池,這個類中把線程池的建立和管理進行了封裝,咱們只須要運用這個類就能夠建立一個線程池並進行管理。另一個接口ThreadFactory主要是用來建立線程的,實現這個接口咱們就擁有了一個線程工廠,建立線程更方便。
2. Java.util.concurrent.Locks:(如下說明摘自API)爲鎖和等待條件提供一個框架的接口和類,它不一樣於內置同步和監視器。該框架容許更靈活地使用鎖和條件,但以更難用的語法爲代價
Lock
接口支持那些語義不一樣(重入、公平等)的鎖規則,能夠在非阻塞式結構的上下文(包括 hand-over-hand 和鎖重排算法)中使用這些規則。主要的實現是 ReentrantLock。
ReadWriteLock
接口以相似方式定義了一些讀取者能夠共享而寫入者獨佔的鎖。此包只提供了一個實現,即 ReentrantReadWriteLock
,由於它適用於大部分的標準用法上下文。但程序員能夠建立本身的、適用於非標準要求的實現。
Condition
接口描述了可能會與鎖有關聯的條件變量。這些變量在用法上與使用 Object.wait 訪問的隱式監視器相似,但提供了更強大的功能。須要特別指出的是,單個 Lock 可能與多個 Condition 對象關聯。爲了不兼容性問題,Condition 方法的名稱與對應的 Object 版本中的不一樣。
AbstractQueuedSynchronizer
類是一個很是有用的超類,可用來定義鎖以及依賴於排隊阻塞線程的其餘同步器。
AbstractQueuedLongSynchronizer
類提供相同的功能但擴展了對同步狀態的 64 位的支持。
前面二者都擴展了類 AbstractOwnableSynchronizer
(一個幫助記錄當前保持獨佔同步的線程的簡單類)。LockSupport
類提供了更低級別的阻塞和解除阻塞支持,這對那些實現本身的定製鎖類的開發人員頗有用。
3. Java.util.concurrent.atomic:(如下內容摘自API)原子類這部分沒有很複雜的類關係,主要是對基礎的int,long,bolean變量,以及相關的數組和對象引用,提供了原子訪問和更新的類。
原子訪問和更新的內存效果通常遵循如下可變規則,正如 The Java Language Specification, Third Edition (17.4 Memory Model) 中的聲明:
除了包含表示單個值的類以外,此包還包含 Updater 類,該類可用於獲取任意選定類的任意選定 volatile 字段上的 compareAndSet 操做
類 AtomicBoolean
、AtomicInteger
、AtomicLong
和 AtomicReference
的實例各自提供對相應類型單個變量的訪問和更新。
類AtomicReferenceFieldUpdater
、AtomicIntegerFieldUpdater
和 AtomicLongFieldUpdater
是基於反射的實用工具,能夠提供對關聯字段類型的訪問。它們主要用於原子數據結構中,該結構中同一節點(例如,樹節點的連接)的幾個 volatile 字段都獨立受原子更新控制。這些類在如何以及什麼時候使用原子更新方面具備更大的靈活性,但相應的弊端是基於映射的設置較爲拙笨、使用不太方便,並且在保證方面也較差。
AtomicIntegerArray
、AtomicLongArray
和 AtomicReferenceArray
類進一步擴展了原子操做,對這些類型的數組提供了支持。這些類在爲其數組元素提供 volatile 訪問語義方面也引人注目,這對於普通數組來講是不受支持的。
AtomicMarkableReference
類將單個布爾值與引用關聯起來。例如,能夠在數據結構內部使用此位,這意味着引用的對象在邏輯上已被刪除。
AtomicStampedReference
類將整數值與引用關聯起來。例如,這可用於表示與更新系列對應的版本號。
花了兩天時間看着一段的API,稍微整理了一下,大部份內容仍是來自API,可是我我的以爲這種東西聽起來很難入門,其實一大部分緣由是咱們沒用從整體上去把握它,從最開始的接口和類的清單表中可能不少東西沒有接觸過,其實那都不是問題,當看到類圖的時候清楚地看到他們之間的父子關係,其實最終須要咱們去掌握的類不是不少。
我我的認爲,數據結構(queue,Map,List)這部分是最容易掌握的,由於它的內部機制已經實現了,咱們只須要知道在什麼場景須要使用它,何時的數據須要用這種併發安全的數據結構在通過不斷地使用就能掌握(深刻理解當我沒說,哈哈)。線程池這部分也很容易掌握,咱們只要熟悉Exeutors類,掌握裏面的方法,就足夠熟練的運用對線程池。而後是原子類,原子類訪問的變量是volited修飾的,原子類實際上就是對數據進行了操做的原子性(操做是一個不可分割的總體,ex:updape包括讀取數據,修改數據,寫回數據三個步驟,普通的操做就不能保證update操做的原子性)一致性的封裝,保證了對這些數據操做的時候是線程安全的。最難的應該是在鎖上,加鎖會形成線程阻塞,高併發狀態下是否該用鎖,和在什麼地方用鎖,鎖的粒度很關鍵,原本只須要在數據上加鎖,而咱們卻加在了方法上,或者對象上,那對性能的影響可能不是一星半點。各類鎖的用法和技巧,帶來的差別,弊端都須要清楚的知道。
但願能給像我同樣還未入門的朋友帶來一點幫助,如今已經基本瞭解了框架,後面就是對這些部分的深刻探索,從具體的應用中看差別,深刻源碼和底層的VM實現看原理,我相信一步步去作必定會逐漸上手。