圖學java基礎篇之併發

概述

併發處理自己就是編程開發重點之一,同時內容也很繁雜,從底層指令處理到上層應用開發都要涉及,也是最容易出問題的地方。這塊知識也是評價一個開發人員水平的重要指標,本人自認爲如今也只是學其皮毛,所以本文重點介紹java的併發相關體系,具體的點懂得就多講,不懂得就給出參考文章。先來看圖:

本文重點介紹jdk中concurrent的內容,併發相關基礎不在介紹,若是想系統的學習,建議直接看併發大做《java併發編程實踐》吧(以前看過,惋惜不少地方沒懂),博客終究只是快餐,加強學習拓展知識很好,但打基礎仍是要看書實戰的。html

java內存模型

直接盜圖一張(圖寢刪),詳細講解參考博客

java內存模型的做用能夠理解爲抽象了線程私有內存與主存(共享內存或堆)的關係,也就是原子性、可見性、順序性的原則,然後介紹的內容都是爲了保證這些原則的實現手段。java

實現多線程的方法

這一塊其實沒必要多說,你們都很熟悉,這裏簡單對比下優缺點:編程

  • 繼承Thread:因爲java不支持多繼承,因此用起來有很強的侷限性,使用場景很少。
  • 實現Runnable接口:經常使用的方式,有點對比Thread,而且更方便實現資源共享(二者異同,重點在評論)
  • 實現Callable接口: 結合Future使用,能夠獲取線程執行結果
  • Executor:concurrent中提供的一個上層併發處理框架,底層也是基於上邊三種實現,基於此實現了線程池、任務調度等類,爲一些典型場景提供了便捷的實現手段。

實現同步的方法

這一塊也是經常使用的,也僅對比介紹一下:數組

  • volatile:volatile保證了原子操做在線程間的可見性(注意僅能保證可見性),而且修飾對象的操做不會指令重排。對於一個原子操做能夠保證其之間一致,可是原子操做真的不多,好比i++都不行。更多介紹
  • Atomic:原子類,,基於CAS原理實現,提供了基本類型和引用對應的類,能保證其基本操做的可見性,底層基於volatile和Unsafe類(一個線程安全相關類,能夠調用底層native方法)。若是線程間的同步僅限於某個值的改變,則可考慮用該類(實際上多數時候即便適合用也能找到對應的上層封裝類,而沒必要本身實現)
  • synchronized:最爲經常使用的同步方法之一,能夠分爲同步方法和同步代碼塊兩類,使用簡單,惟一必定要搞清的是synchronized鎖的對象是誰。(拓展:synchronized底層實現
  • wait/notify:同步幾大原語之二(記得還有join吧),java的Object中已實現的native方法,經常使用來同步線程執行順序或進度,然而多數場景concurrent也提供了對應工具類,因此通常使用時也應該優先使用對應的工具類
  • Lock:鎖,主要有ReentrantLock和ReadWriteLock,該方式較synchronized的優點就是使用比較靈活,同步再也不侷限於代碼塊或者方法,能夠在任何須要的地方加鎖解鎖。就性能方面,除非你用的是1.4以前的jdk,不然二者差別不大
  • ThreadLocal:線程本地變量,其內部是一個map,key爲線程對象自己,value爲對應變量的一個拷貝,每一個線程使用該變量時實際使用的是其副本,以此解決多線程共享變量的競爭,須要注意的是改類型並非解決同步問題的,而是解決資源共享問題的,每一個線程使用各自的副本,相互之間不影響,可是該變量的值變化相互之間也是隔離的ThreadLocal深刻剖析

concurrent包

JDK 1.5增長了java.util.concurrent包,其內部提供了大量併發相關類,大大簡化了設計併發的程序開發。該包大體可分爲四大塊:Atomic、Lock、Executor、以及線程安全的集合類,因爲集合類已經在該系列第一篇介紹過,所以這裏重點介紹前三塊,此外還有一些工具類,這裏僅介紹幾個常見的。安全

Atomic

前邊已經介紹過,Atomic爲修飾的對象提供了原子更新,保證了其更新在線程間的可見性,Atomic包內的原子類實現主要基於CAS原理,利用了Unsafe包提供的CAS方法,其中能夠分爲如下幾類:多線程

  • 原子更新基本類型類,提供了AtomicBoolean、AtomicInteger和AtomicLong,對於其餘基本類型,能夠參照其實現自行經過Unsafe的方法實現(實質上都是轉成int處理)
  • 原子更新數組類:也提供了三種類型:AtomicIntegerArray、AtomicLongArray和AtomicReferenceArray
  • 原子更新引用類型:對於非基本類型提供的類,AtomicReference、AtomicReferenceFieldUpdater、AtomicMarkableReference
  • 原子更新字段類:這幾個類主要用於更新類中的某個字段:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference
    這些類使用方法相似,都是經過如下方法實現原子更新:
  • getAndSet(v):設置新值,返回舊值
  • compareAndSet(expectedValue, newValue):若是當前值(current value)等於期待的值(expectedValue), 則原子地更新指定值爲新值(newValue), 若是更新成功,返回true, 不然返回false, 換句話能夠這樣說: 將原子變量設置爲新的值, 可是若是從我上次看到的這個變量以後到如今被其餘線程修改了(和我指望看到的值不符), 那麼更新失敗
    詳細的使用能夠參考Java中的Atomic包使用指南

Lock

Lock提供了一種更爲靈活的同步方式,Lock下主要有如下類:併發

  • ReentrantLock:重入鎖,其底層經過一個Sync的靜態類實現加鎖解鎖。Sync繼承自AbstractQueuedSynchronizer,該抽象類內部實現了一個鏈表,保存了請求獲取鎖的狀態,同時其內部有一個狀態值,用來表示鎖是否被線程獲取,其修改經過Unsafe包提供的CAS方法,以此能夠保證其可見性。同時尤爲內部實現也能夠知道,之因此叫重入鎖,是由於其提供了非阻塞的使用方式,若是使用tryLock方法,當lock時在發現鎖已lock的狀況下,會當即返回結果,而不會阻塞。使用示例
  • ReentrantReadWriteLock:可重入讀寫鎖。實現原理和ReentrantLock同樣,再次基礎上增長了讀寫鎖的操做。使用示例
  • Condition:實現類是AbstractQueuedSynchronizer中的一個內部類,其功能是實現線程間的協調通訊,使得某個,或者某些線程一塊兒等待某個條件(Condition),只有當該條件具有( signal 或者 signalAll方法被帶調用)時 ,這些等待線程纔會被喚醒,從而從新爭奪鎖。使用示例
  • LockSupport:能夠看作對Unsafe包中併發原語的封裝,爲上層的鎖實現提供原語操做。通常狀況下上層開發不多用到。

Executor

Executor框架是concurrent中最經常使用的內容之一,其提供了一套可以便捷管理線程和任務的類,使咱們可以很方便建立、調度一批具備同類操做的線程。其主要有如下幾個類(接口):框架

  • Callable、Future:前邊已經介紹過了,提供了一種能夠獲取返回值的線程實現方法,通常與
    ExecutorService配合使用。Callable使用
  • Executor:線程工具類,主要用於線程池、ThreadFactory、Callable實例。Executors詳解
  • ThreadFactory:接口類,提供了建立線程個工廠類,可能是時候配合線程池,做爲參數傳入爲線程池提供建立線程的方法。
  • ExecutorService:接口類,是線程池實現類ThreadPoolExecutor的基類。
  • ExecutorCompletionService:與ExecutorService功能同樣,不過其提供了poll()和take()兩個方法用於獲取線程執行結果,前者是非阻塞的,後者是阻塞的。
    使用示例

other

此外concurrent包還提供了一些其餘類,這裏僅列出功能,具體的使用可自行查詢,這裏給出一個比較完善的總結java.util.concurrent 用戶指南工具

  • ForkJoinPool:和ExecutorService相似,不過其提供了fork和join的功能,可以將池內指定級別的任務進行分解或合併。這種處理方式與目前不少流處理框架相似,不過該實現使用的很少。
  • CountDownLatch:CountDownLatch 是一個線程協調器,它容許一個或多個線程等待一系列指定操做的完成。
    CountDownLatch 以一個給定的數量初始化。countDown() 每被調用一次,這一數量就減一。經過調用await() 方法之一,線程能夠阻塞等待這一數量到達零。
  • CyclicBarrier:CyclicBarrier類也是一種同步機制,它能夠在指定位置設定barrier,只有全部線程都執行到該位置是,纔會繼續向下執行。
  • Exchanger:該類提供了線程間交換數據的方法,能夠視做一個管道。實現原理
  • Semaphore:信號量,學過操做系統的都知道,實現生產者—消費者的經常使用手段之一,信號量最大的用處是能夠控制資源的訪問數量,比起阻塞隊列更加靈活。使用示例

其餘

正如最開始所說的,併發相關的知識毫不是看一些知識點就能夠掌握的,若是想要真正掌握,必須系統的學習。這裏只是列出一些java相關的知識點,僅供參考。
最後再附兩篇博文,有興趣的能夠看下:性能

相關文章
相關標籤/搜索