1. 程式人生 > >並發編程的藝術第七章-13個原子類介紹

並發編程的藝術第七章-13個原子類介紹

13 原子類

java中的13個原子類操作

13個原子類操作主要分為四大類:原子更新基本類型,原子更新數組,原子更新引用,原子更新屬性(字段)

atomic 的類基本都是unsafe類的包裝類

原子更新基本類型包括:

atomicBoolean

atomicIneger

atomicLong

這裏註意lazyset方法,Doug Lea大神已經在oracle官網解釋了,原文如下

"As probably the last little JSR166 follow-up for Mustang, we added a "lazySet" method to the Atomic classes (AtomicInteger, AtomicReference, etc). This is a niche method that is sometimes useful when fine-tuning code using non-blocking data structures. The semantics are that the write is guaranteed not to be re-ordered with any previous write, but may be reordered with subsequent operations (or equivalently, might not be visible to other threads) until some other volatile write or synchronizing action occurs). The main use case is for nulling out fields of nodes in non-blocking data structures solely for the sake of avoiding long-term garbage retention; it applies when it is harmless if other threads see non-null values for a while, but you‘d like to ensure that structures are eventually GCable. In such cases, you can get better performance by avoiding the costs of the null volatile-write. There are a few other use cases along these lines for non-reference-based atomics as well, so the method is supported across all of the AtomicX classes. For people who like to think of these operations in terms of machine-level barriers on common multiprocessors, lazySet provides a preceeding store-store barrier (which is either a no-op or very cheap on current platforms), but no store-load barrier (which is usually the expensive part of a volatile-write)." ###@###.### 2005-05-24 17:04:

外鏈地址如下

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6275329

大概意思就是使用該方法取掉了 storeload屏障,只保留storestore屏障,

在屏障中storeload屏障是最耗資源的,因此使用該方法對提高效率有一定好處,雖然不能保證寫完之後立即被其他線程可見,但是能保證寫的順序,同時該方法職能處理有volatile的對象,使用該方法要註意一定的使用場景。

典型的atomicInteger的getAndIncrement方法如下

public final int getAndIncrement(){

int current=get();

while(true){

if(compareandset(current,current+1)){

return current;

}

}

//compareandset 使用unsafe類實現

public final boolean compareandset(int expect ,int update){

unsafe.compareandswapint(this,expect,valueoffset,update);

}

}

根據unsafe類提供的swap方法,在使用時需要將包裝類轉換成基本類型再使用unsafe類中的compareandswap方法

在atomic包中,並沒有提供 char float double 類型的swap方法,可以采用轉換成object包裝類,或者轉換成long類型進行處理

更新原子數組類

AtomicIntegerArray

AtomicLongArray

AtomicReferenceArray

//使用代碼實例

public class AtomicIntegerArrayTest{

static int[] value=new int[2]{1,2};

static AtomicIntegerArray ai = new AtomicInteger(value);

public static void main(String[] args){

ai.getandset(0,3);//設置第一位為3

System.out.println(ai.get(0));// 結果3

System.out.println(value[0]);//結果1

}

}

根據偽代碼結果發現結果不一致,主要原因:ai通過構造方法復制了一份value所以對ai修改時,不會影響value的值

原子更新引用類型

原子更新基本類型的AtomicInteger,只能更新一個變量,如果更新多個變量就需要使用原子更新引用類

AtomicReference 原子更新引用類型

AtomicReferenceFieldUpdater 原子更新引用對象裏的字段

AtomicMarkableReference 原子更新帶有標記位的引用類型

原子更新引用類型的字段

如果需要原子更新引用對象的字段時,就需要使用原子更新字段類,atomic包包含了以下工具類

AtomicIntegerFieldUpdater

AtomicLongFieldUpdate

AtomicStampedReference:原子更新帶有版本號的引用類型,可用於原子更新的版本號和引用數據,可以有效解決原子更新的aba問題。原子更新主要分為兩步:因為原始更新字段類都是抽象類,必須使用靜態方法 newUpdater()創建一個更新器,並且需要設置更新器的類型和屬性,第二步,更新類的字段必須使用 public volatitle字段進行修飾

調用偽代碼如下:

public class FieldUpdater{

AtomicIntegerFieldUpdater a = AtomicIntegerFieldUpdater.newUpdater(User.class,age);

static class User{

private String name;

private volatitle int age;

}

public static void main(String[] args){

User coman = new User("coman",10);

System.out.println(a.getAndIncrement(coman));

System.out.println(a.get(coman));

}

}


本文出自 “iter工作總結” 博客,請務必保留此出處http://5855156.blog.51cto.com/5845156/1962250

並發編程的藝術第七章-13個原子類介紹