[Java多線程]-學習多線程須要來了解哪些東西?(concurrent併發包的數據結構和線程池,Locks鎖,Atomic原子類)

前言:剛學習了一段機器學習,最近須要重構一個java項目,又趕過來看java。大可能是線程代碼,沒辦法,那時候總以爲多線程是個很難的部分不多用到,因此一直沒下決定去啃,那些年留下的坑,老是得本身跳進去填一次。html

思路:大概看了線程相關的一些知識,對線程的運行機制,同步機制,以及整個系統都作一個全面的瞭解。在深刻每個部分去看一下線程及其相關包的源碼作深刻了解。java

目標:線程,併發包(線程池,併發的數據結構,鎖,原子類)程序員

   經過一些資料的查看最終把目標定位在線程和併發包上,線程是核心,併發包是輔助工具,用於多線程運行時的併發問題。其實這樣看來多線程並無不少的東西,支持併發的數據結構用於保證數據的安全性,各類鎖機制用來保證類,對象,方法,屬性的併發安全。它的難點主要是在運用上,各類鎖機制的運用,會給系統帶來負擔,也會給程序性能帶來影響,可是同時又要保證數據的同步。鎖機制使用的強度和位置,直接決定了併發系統的好壞。web

java中文APIhttp://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> 提供其餘原子 putIfAbsentremovereplace 方法的 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 根據須要建立新線程的對象。
類摘要
AbstractExecutorService 提供 ExecutorService 執行方法的默認實現。
ArrayBlockingQueue<E> 一個由數組支持的有界阻塞隊列
ConcurrentHashMap<K,V> 支持獲取的徹底併發和更新的所指望可調整併發的哈希表。
ConcurrentLinkedQueue<E> 一個基於連接節點的無界線程安全隊列
ConcurrentSkipListMap<K,V> 可縮放的併發 ConcurrentNavigableMap 實現。
ConcurrentSkipListSet<E> 一個基於 ConcurrentSkipListMap 的可縮放併發 NavigableSet 實現。
CopyOnWriteArrayList<E> ArrayList 的一個線程安全的變體,其中全部可變操做(addset 等等)都是經過對底層數組進行一次新的複製來實現的。
CopyOnWriteArraySet<E> 對其全部操做使用內部 CopyOnWriteArrayList 的 Set
CountDownLatch 一個同步輔助類,在完成一組正在其餘線程中執行的操做以前,它容許一個或多個線程一直等待。
CyclicBarrier 一個同步輔助類,它容許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。
DelayQueue<E extends Delayed> Delayed 元素的一個無界阻塞隊列,只有在延遲期滿時才能從中提取元素。
Exchanger<V> 能夠在對中對元素進行配對和交換的線程的同步點。
ExecutorCompletionService<V> 使用提供的 Executor 來執行任務的 CompletionService
Executors 此包中所定義的 ExecutorExecutorServiceScheduledExecutorServiceThreadFactory 和 Callable 類的工廠和實用方法。
FutureTask<V> 可取消的異步計算。
LinkedBlockingDeque<E> 一個基於已連接節點的、任選範圍的阻塞雙端隊列
LinkedBlockingQueue<E> 一個基於已連接節點的、範圍任意的 blocking queue
PriorityBlockingQueue<E> 一個無界阻塞隊列,它使用與類 PriorityQueue 相同的順序規則,而且提供了阻塞獲取操做。
ScheduledThreadPoolExecutor ThreadPoolExecutor,它可另行安排在給定的延遲後運行命令,或者按期執行命令。
Semaphore 一個計數信號量。
SynchronousQueue<E> 一種阻塞隊列,其中每一個插入操做必須等待另外一個線程的對應移除操做 ,反之亦然。
ThreadPoolExecutor 一個 ExecutorService,它使用可能的幾個池線程之一執行每一個提交的任務,一般使用 Executors 工廠方法配置。
ThreadPoolExecutor.AbortPolicy 用於被拒絕任務的處理程序,它將拋出 RejectedExecutionException.
ThreadPoolExecutor.CallerRunsPolicy 用於被拒絕任務的處理程序,它直接在 execute 方法的調用線程中運行被拒絕的任務;若是執行程序已關閉,則會丟棄該任務。
ThreadPoolExecutor.DiscardOldestPolicy 用於被拒絕任務的處理程序,它放棄最舊的未處理請求,而後重試 execute;若是執行程序已關閉,則會丟棄該任務。
ThreadPoolExecutor.DiscardPolicy 用於被拒絕任務的處理程序,默認狀況下它將丟棄被拒絕的任務。
枚舉摘要
TimeUnit TimeUnit 表示給定單元粒度的時間段,它提供在這些單元中進行跨單元轉換和執行計時及延遲操做的實用工具方法。

2.   java.util.concurrent.locks併發

接口摘要
Condition Condition 將 Object 監視器方法(waitnotify 和 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) 中的聲明:

    • get 具備讀取 volatile 變量的內存效果。
    • set 具備寫入(分配)volatile 變量的內存效果。
    • 除了容許使用後續(但不是之前的)內存操做,其自身不施加帶有普通的非 volatile 寫入的從新排序約束,lazySet 具備寫入(分配)volatile 變量的內存效果。在其餘使用上下文中,當爲 null 時(爲了垃圾回收),lazySet 能夠應用不會再次訪問的引用。
    • weakCompareAndSet 以原子方式讀取和有條件地寫入變量但 建立任何 happen-before 排序,所以不提供與除 weakCompareAndSet 目標外任何變量之前或後續讀取或寫入操做有關的任何保證。
    • compareAndSet 和全部其餘的讀取和更新操做(如 getAndIncrement)都有讀取和寫入 volatile 變量的內存效果。

  除了包含表示單個值的類以外,此包還包含 Updater 類,該類可用於獲取任意選定類的任意選定 volatile 字段上的 compareAndSet 操做

  類 AtomicBooleanAtomicIntegerAtomicLong 和 AtomicReference 的實例各自提供對相應類型單個變量的訪問和更新。

  AtomicReferenceFieldUpdaterAtomicIntegerFieldUpdater 和 AtomicLongFieldUpdater 是基於反射的實用工具,能夠提供對關聯字段類型的訪問。它們主要用於原子數據結構中,該結構中同一節點(例如,樹節點的連接)的幾個 volatile 字段都獨立受原子更新控制。這些類在如何以及什麼時候使用原子更新方面具備更大的靈活性,但相應的弊端是基於映射的設置較爲拙笨、使用不太方便,並且在保證方面也較差。

   AtomicIntegerArrayAtomicLongArray 和 AtomicReferenceArray 類進一步擴展了原子操做,對這些類型的數組提供了支持。這些類在爲其數組元素提供 volatile 訪問語義方面也引人注目,這對於普通數組來講是不受支持的。

  AtomicMarkableReference 類將單個布爾值與引用關聯起來。例如,能夠在數據結構內部使用此位,這意味着引用的對象在邏輯上已被刪除。

  AtomicStampedReference 類將整數值與引用關聯起來。例如,這可用於表示與更新系列對應的版本號。

 

 花了兩天時間看着一段的API,稍微整理了一下,大部份內容仍是來自API,可是我我的以爲這種東西聽起來很難入門,其實一大部分緣由是咱們沒用從整體上去把握它,從最開始的接口和類的清單表中可能不少東西沒有接觸過,其實那都不是問題,當看到類圖的時候清楚地看到他們之間的父子關係,其實最終須要咱們去掌握的類不是不少。 

  我我的認爲,數據結構(queue,Map,List)這部分是最容易掌握的,由於它的內部機制已經實現了,咱們只須要知道在什麼場景須要使用它,何時的數據須要用這種併發安全的數據結構在通過不斷地使用就能掌握(深刻理解當我沒說,哈哈)。線程池這部分也很容易掌握,咱們只要熟悉Exeutors類,掌握裏面的方法,就足夠熟練的運用對線程池。而後是原子類,原子類訪問的變量是volited修飾的,原子類實際上就是對數據進行了操做的原子性(操做是一個不可分割的總體,ex:updape包括讀取數據,修改數據,寫回數據三個步驟,普通的操做就不能保證update操做的原子性)一致性的封裝,保證了對這些數據操做的時候是線程安全的。最難的應該是在鎖上,加鎖會形成線程阻塞,高併發狀態下是否該用鎖,和在什麼地方用鎖,鎖的粒度很關鍵,原本只須要在數據上加鎖,而咱們卻加在了方法上,或者對象上,那對性能的影響可能不是一星半點。各類鎖的用法和技巧,帶來的差別,弊端都須要清楚的知道。

  但願能給像我同樣還未入門的朋友帶來一點幫助,如今已經基本瞭解了框架,後面就是對這些部分的深刻探索,從具體的應用中看差別,深刻源碼和底層的VM實現看原理,我相信一步步去作必定會逐漸上手。

相關文章
相關標籤/搜索