1. 無鎖類的原理詳解
1.1.cas
cas演算法的過程是這樣:它包含
3個引數
cas(v,e,n)。v
表示要更新的變數,
e表示預期值,
n表示新值。僅當
v 值等於
e值時,才會將
v的值設為
n,如果v值和
e值不同,則說明已經有其他執行緒做了更新,則當前執行緒什麼 都不做。最後,
cas返回當前
v的真實值。
cas操作是抱著樂觀的態度進行的,它總是認為自己可以成功完成 操作。當多個執行緒同時使用
cas操作乙個變數時,只有乙個會勝出,並成功更新,其餘均會失敗。失敗的執行緒 不會被掛起,僅是被告知失敗,並且允許再次嘗試,當然也允許失敗的執行緒放棄操作。基於這樣的原理,
cas
操作即時沒有鎖,也可以發現其他執行緒對當前執行緒的干擾,並進行恰當的處理。
1.2.cpu指令
cas操作不會涉及執行緒安全的問題,因為cas操作是通過一條cpu指令進行的。
2. 無鎖類的使用
2.1.atomicinteger
2.1.1. 概述
atomicinteger 和integer都是實現了number介面。
2.1.2. 主要方法
public final int get() //取得當前值
public final void set(int newvalue) //設定當前值
public final int getandset(int newvalue) //設定新值,並返回舊值
public final boolean compareandset(int expect, int u) //如果當前值為expect,則設定為u
public final int getandincrement() //當前值加1,返回舊值
public final int getanddecrement() //當前值減1,返回舊值
public final int getandadd(int delta) //當前值增加delta,返回舊值
public final int incrementandget() //當前值加1,返回新值
public final int decrementandget() //當前值減1,返回新值
public final int addandget(int delta) //當前值增加delta,返回新值
2.2.unsafe
2.2.1. 概述
非安全的操作,比如:
根據偏移量設定值
park()
底層的cas操作
非公開api,在不同版本的
jdk中, 可能有較大差異
2.2.2. 主要介面
//獲得給定物件偏移量上的int值
public native int getint(object o, long offset);
//設定給定物件偏移量上的int值
public native void putint(object o, long offset, int x);
//獲得欄位在物件中的偏移量
public native long objectfieldoffset(field f);
//設定給定物件的int值,使用volatile語義
public native void putintvolatile(object o, long offset, int x);
//獲得給定物件物件的int值,使用volatile語義
public native int getintvolatile(object o, long offset);
//和putintvolatile()一樣,但是它要求被操作字段就是volatile型別的
public native void putorderedint(object o, long offset, int x);
2.3.atomicreference
2.3.1. 概述
對引用進行修改
是乙個模板類,抽象化了資料型別
2.3.2. 主要介面
get()
set(v)
compareandset()
getandset(v)
2.4.atomicstampedreference
2.4.1. 概述
我們會發現cas操作還是有乙個問題的
比如之前的atomicinteger的incrementandget方法
假設當前value=1當某執行緒int current = get()執行後,切換到另乙個執行緒,這個執行緒將1變成了2,然後又乙個執行緒將2又變成了1。此時再切換到最開始的那個執行緒,由於value仍等於1,所以還是能執行cas操作,當然加法是沒有問題的,如果有些情況,對資料的狀態敏感時,這樣的過程就不被允許了。
2.4.2. 主要介面
//比較設定 引數依次為:期望值 寫入新值 期望時間戳 新時間戳
public boolean compareandset(v expectedreference,v newreference,int expectedstamp,int newstamp)
//獲得當前物件引用
public v getreference()
//獲得當前時間戳
public int getstamp()
//設定當前物件引用和時間戳
public void set(v newreference, int newstamp)
2.5.atomicintegerarray
2.5.1. 概述
支援無鎖的陣列
2.5.2. 主要介面
//獲得陣列第i個下標的元素
public final int get(int i)
//獲得陣列的長度
public final int length()
//將陣列第i個下標設定為newvalue,並返回舊的值
public final int getandset(int i, int newvalue)
//進行cas操作,如果第i個下標的元素等於expect,則設定為update,設定成功返回true
public final boolean compareandset(int i, int expect, int update)
//將第i個下標的元素加1
public final int getandincrement(int i)
//將第i個下標的元素減1
public final int getanddecrement(int i)
//將第i個下標的元素增加delta(delta可以是負數)
public final int getandadd(int i, int delta)
2.6.atomicintegerfieldupdater
2.6.1. 概述
讓普通變數也享受原子操作
2.6.2. 主要介面
atomicintegerfieldupdater.newupdater()
incrementandget()
2.6.3. **明
1. updater只能修改它可見範圍內的變數。因為
updater
使用反射得到這個變數。如果變數不可見,就會出錯。 比如如果
score
申明為private
,就是不可行的。
2. 為了確保變數被正確的讀取,它必須是
volatile
型別的。如果我們原有**中未申明這個型別,那麼簡單得 申明一下就行,這不會引起什麼問題。
3. 由於
cas操作會通過物件例項中的偏移量直接進行賦值,因此,它不支援
static
字段(unsafe. objectfieldoffset()
不支援靜態變數)。
ios 多執行緒之四 執行緒鎖
假如我們在功能的實現過程中,類中有乙個全域性變數,我們建立了多個執行緒去同時改變或者使用這個變數,會出現什麼問題?執行緒鎖就是用來解決多執行緒之間對資源共享的問題 在上文 多執行緒之三 的基礎之上進行演示,模仿多個地點進行售票的案例。1 建立按鈕 問題 當多個執行緒執行某一塊相同 需要執行緒鎖進行保...
多執行緒之鎖機制
多執行緒實現方式的其中之一是實現runnable方式,並且重寫run方法 package thrad author 子曰無衣 public class mythread implements runnable public mythread string name override public s...
多執行緒之互斥鎖
當執行緒之間需要用到共同的變數時,不希望某乙個執行緒使用時,被其它執行緒給呼叫,就需要互斥鎖來保證共享資源該執行緒使用完後,再給其它執行緒使用 典型例子 由於執行緒是獲取到作業系統分配的cpu時間片是才會執行,所以單cpu的情況下,多執行緒同步其實並非同步,當其中乙個執行緒1執行的時候,可能會中途跳...