多執行緒之四 無鎖的簡單介紹

2021-08-20 03:41:55 字數 4024 閱讀 3198

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執行的時候,可能會中途跳...