java併發-CAS的理解

在Java方面,能夠實現多線程安全修改對象值得方法只有2個

1.原子操作

2.互斥方法

而在Java當中,或是其他語言中,基本上也都是使用CAS實現。CAS是比較並交換的意思,這個操作包含2個連續的操作,比較,還有賦值,因爲2個操作在cpu指令級別支持,所以能夠實現原子操作。

這裏比較和賦值的是內存,而不是cpu的緩存,這裏需要注意。當然,其操作的副作用能夠更新所有cpu緩存爲內存中的值,或是標記緩存中的值爲已失效,具體實現,難以猜想。

CAS包含最基本的3個操作數,內存地址,期望的值,將要更新的新值。

而在java語言中,無法直接獲得內存地址,所以,要用對象引用,加字段引用來間接表示內存地址。所以,在Java的cas操作上,要有4個操作數。

1.將要作用的對象

2.將要作用的對象的字段(這裏又間接了一步,需要獲得字段的偏移量)

3.期望的值

4.將要更新的值

使用Unsafe來進行操作。

首先,定義獲得Unsafe對象

private static final Unsafe unsafe = Unsafe.getUnsafe();

然後,使用long定義字段偏移量

private static final long stateOffset;

然後,靜態代碼塊獲得字段偏移量

static{

  stateOffset = unsafe.objectFieldOffset(AbstractQueuedSynchronizer.class.getDeclaredField("state"));

}

最後,在適當的地方調用

unsafe.compareAndSwapInt(this, stateOffset, expect, update);

當更新成功,返回true,更新失敗返回false,當多個線程同時操作時,只有一個線程返回true,而其他的線程都返回false,也就是隻有一個線程能夠成功。

具體哪個線程能夠成功,真的很難判斷,基本上都是cpu級別的實現方式。

雖然我們不知道具體是什麼原因導致只有一個線程能夠安全的更新,返回true,當我們能夠利用它來保證安全的更新一個變量的值,而不被多線程破壞。

當我們有一個變量叫stat時,我們執行如下代碼時,思考作用

if(compareAndSet(0,1)){

  //這裏,只有一個線程能夠進入到這裏

}else{

  //這裏,其他同時進入,或是其後進入的線程,必定來到這裏

}

compareAndSet(0,1)會只讓一個線程更新,然後做一些處理代碼,而其他的線程卻不能!!!如果,我們要在多線程環境下,讓一個線程原子的更新某個值得同時做一些事情,我們就可以利用

comapreAndSet來進行工作。

而如下代碼

if(state == 0){

  //合理做一些事情

  state == 1;

}else{

}

這樣的代碼,不能夠唯一的保證只有一個線程能夠進入第一個分支代碼處,除非多線程互斥訪問這段代碼。所以,compareAndSet的好處就是原子讓一個線程更新並且返回值可以用來進行後續代碼處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章