java並發編程(四)

  • 2020 年 3 月 11 日
  • 筆記

根據課程大綱整理資料。

21:volatile關鍵字的可見性

volatile 解決的是多核CPU帶來的快取與CPU之間數據的可見性,實現禁止指令重排

volatile即記憶體屏障,可保證一段記憶體中一個變數的原子性,原生類型都是原子性的。所以java中 volatile long,volatile double都是執行緒安全的。

22:volatile與static的關係

volatile 是保證從主記憶體載入到執行緒工作記憶體的值是最新的,此時並未載入並刷新到主記憶體中,static表示當前類的實例在主記憶體中用的是同一份。只能保證變數的來源,volatile, 聲明變數值的一致性;static,聲明變數的唯一性。

23:Atomic的原子性

原生類型都是原子性,以AtomicInteger為例

{@link java.util.concurrent.atomic} package specification for   * description of the properties of atomic variables

getAndIncrement()方法會原子性的進行增量操作把當前值加1。Atomic要跟CAS放在一起

public final int getAndAdd(int delta) {          return unsafe.getAndAddInt(this, valueOffset, delta);      }

24:CAS Compare and Swap

private static final Unsafe unsafe

private volatile int value;

unsafe類是CAS的核心類,是由C語言native方法來訪問的

public final int getAndAddInt(Object var1, long var2, int var4) {          int var5;          do {              var5 = this.getIntVolatile(var1, var2);          } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));            return var5;      }

其中getAndAddInt方法,this表示當前對象valueoffset表示記憶體中的偏移地址,delta是當前value增加的變數

CAS即比較當前值與預設值,交換並增加,如果與預想一致就交換,否則再次自旋,所以帶來循環開銷問題,進而引來ABA問題。

25:Threadlocal

這個類提供執行緒局部變數。 這些變數與其正常的對應方式不同,因為訪問一個的每個執行緒(通過其get或set方法)都有自己獨立初始化的變數副本。 ThreadLocal實例通常是希望將狀態與執行緒關聯的類中的私有靜態欄位(例如,用戶ID或事務ID)

1.如果多個執行緒訪問同一個共享Threadlocal變數,是保證執行緒隔離的,A,B,C訪問的即Threadlocal的變數副本

2.與執行緒狀態相關,單個執行緒內,該執行緒持有該資源變數是私有的

Threadlocal並不是為了保證執行緒安全,而是為了在執行緒內方便共享變數跨方法的傳遞

經典用法:@Transactional事務的處理,利用其get方法獲取Entry[],為每一個執行緒提供變數的副本,實現執行緒的隔離,每個執行緒只訪問自己的數據。

26:InheritableThreadLocal與Threadlocal

首先InheritableThreadLocal繼承了Threadlocal,Inheritable本身即是繼承的意思,

/**   * This class extends <tt>ThreadLocal</tt> to provide inheritance of values   * from parent thread to child thread: when a child thread is created, the   * child receives initial values for all inheritable thread-local variables   * for which the parent has values.  Normally the child's values will be   * identical to the parent's; however, the child's value can be made an   * arbitrary function of the parent's by overriding the <tt>childValue</tt>   * method in this class.   *   * <p>Inheritable thread-local variables are used in preference to   * ordinary thread-local variables when the per-thread-attribute being   * maintained in the variable (e.g., User ID, Transaction ID) must be   * automatically transmitted to any child threads that are created.   *   * @author  Josh Bloch and Doug Lea   * @see     ThreadLocal   * @since   1.2   */    public class InheritableThreadLocal<T> extends ThreadLocal<T> {            ...  }

創建子執行緒時,子執行緒接收所有可繼承執行緒局部變數的初始值。

說實話第一次聽到跟他比較,比如ThreadLocal VS FastThreadlocal,既然是繼承,大多是為了擴展父類方法,解決其threadlocal.get()得不到其新執行緒中的值,

推薦部落格:  https://blog.csdn.net/ni357103403/article/details/51970748

27:Unsafe類詳解

Unsafe類除了CAS理解相關以外,確實了解的不多,這裡推薦美團技術部落格

Java魔法類:Unsafe應用解析  https://tech.meituan.com/2019/02/14/talk-about-java-magic-class-unsafe.html

它屬於native.C語言編寫的類,在cas,netty中都有應用。這裡提到了執行緒調度可用於執行緒掛起,真實調用了park()方法實現。

28:同步類容容器

CopyOnWriteArraySet

ConcurentSkipListSet

ConcurrentHashMap

與 ConcurrentSkipListMap

ConcurrentHashMap 加鎖

ConcurrentSkipListMap 不需要加鎖,浪費空間

29:ConcurrentHashMap

Hashmap是並發執行緒不安全的,其無法解決共享變數的安全問題,那麼解決的方法為

1.替換為Hashtable

2.Collections.synchronizedMap()

3.ConcurrentHashMap

其中Hashtable之所以安全因為其put,get等大多數方法為synchronized

修飾的,但並發場景下鎖的粒度太重,性能降低

Collections.synchronizedMap()

public static void main(String[] args) {     HashMap<String, String> map = new HashMap<>();     Map<String, String> synchronizedMap = Collections.synchronizedMap(map);  }

其put方法get方法也都是synchronized

 public V put(K key, V value) {              synchronized (mutex) {return m.put(key, value);}   }    public V get(Object key) {              synchronized (mutex) {return m.get(key);}   }

ConcurrentHashMap

1.7是鎖分段 segment 16,隔離級別太大,有很多空間就浪費了,太小就段內的元素過多

1.8以後是cas演算法C語言寫得,無鎖演算法,put添加的時候,鏈表+紅黑樹

put方法(無鎖添加)

29:無阻塞隊列ConcurrentLinkedQueue

An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.   * This queue orders elements FIFO (first-in-first-out).  public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>          implements Queue<E>, java.io.Serializable {    }

一個為綁定執行緒安全的隊列,隊列的元素先進先出

看其節點的內部方法

 /**    * Constructs a new node.  Uses relaxed write because item can    * only be seen after publication via casNext.   */   Node(E item) {              UNSAFE.putObject(this, itemOffset, item);          }  構造新節點。使用輕鬆寫入,因為item可以僅在通過casNext發布後才能看到

那其實還是跟Unsafe類離不開。

推薦部落格http://ifeve.com/concurrentlinkedqueue/
我沒有夢見你,  但我夢見了糖葫蘆,  醒來我突然覺得我好久沒吃過糖葫蘆了  然後就想跟你講一下  可能  你和糖葫蘆一樣甜吧

Tags: