1. AtomicInteger
API
public final int get() //取得当前值
public final void set(int newValue) //设置当前值
public final int getAndSet(int newValue) //设置新值,并返回旧值public final boolean compareAndSet(int expect, int updated)//如果当前值为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,返回新值
方法实现
- public final int getAndUpdate(IntUnaryOperator updateFunction) {
- int prev, next;
- do {
- prev = get();
- next = updateFunction.applyAsInt(prev);
- } while (!compareAndSet(prev, next));
- return prev;
- }
-
- public final boolean compareAndSet(int expect, int update) {
- return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
- }
-
- private static final Unsafe unsafe = Unsafe.getUnsafe();
- private static final long valueOffset;
-
- static {
- try {
- valueOffset = unsafe.objectFieldOffset
- (AtomicInteger.class.getDeclaredField("value"));
- } catch (Exception ex) { throw new Error(ex); }
- }
-
- private volatile int value;
2. Unsafe类
概述:非安全的操作,比如:
根据偏移量设置值
park()
底层的CAS操作
非公开API,在不同版本的JDK中, 可能有较大差异
主要方法
//获得给定对象偏移量上的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);
3. AtomicReference
概述:对引用进行修改
是一个模板类,抽象化了数据类型
主要方法:
get()
set(V)compareAndSet()
getAndSet(V)
使用用例:
- static AtomicReference<Integer> money = new AtomicReference<Integer>();
-
- money.set(19);
-
- for(int i=0; i<3; i++) {
- new Thread() {
- public void run() {
- while(true) {
- while(true) {
- Integer m = money.get();
- if(m<20) {
- if(money.compareAndSet(m, m+20)) {
- System.out.println("余额小于20元,充值成功,余额:"+ money.get() + "元");
- break;
- } else {
- break;
- }
- }
- }
- }
- };
- }.start();
-
-
-
-
- new Thread() {
- public void run() {
- for (int j = 0; j < 100; j++) {
- while(true) {
- Integer m = money.get();
- if(m>10) {
- System.out.println("大于10元");
- if(money.compareAndSet(m, m-10)) {
- System.out.println("成功消费10元,余额:" + money.get());
- break;
- }
- } else {
- System.out.println("没有足够金额");
- break;
- }
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
-
- }
- }
- };
- }.start();
-
4. AtomicStampedReferencea. ABA问题
b. 主要方法
//比较设置参数依次为:期望值写入新值期望时间戳新时间戳
public boolean compareAndSet(V expectedReference,V newReference,int expectedStamp,int newStamp)
//获得当前对象引用
public V getReference()
//获得当前时间戳
public int getStamp()
//设置当前对象引用和时间戳
public void set(V newReference, int newStamp)
c. 使用用例
- //比较设置参数依次为:期望值 写入新值 期望时间戳 新时间戳
- public boolean compareAndSet(V expectedReference,
- V newReference,
- int expectedStamp,
- int newStamp)
- //获得当前对象引用
- public V getReference()
- //获得当前时间戳
- public int getStamp()
- //设置当前对象引用和时间戳
- public void set(V newReference, int newStamp)
- 使用AtomicStampedReference来修正那个贵宾卡充值的问题:
- public class AtomicStampedReferenceDemo {
- static AtomicStampedReference<Integer> money = new AtomicStampedReference<Integer>(19,0);
- public static void main(String[] args) {
- for(int i=0; i<3; i++) {
- final int timestamp = money.getStamp();
- new Thread() {
- public void run() {
- while(true) {
- while(true) {
- Integer m = money.getReference();
- if(m<20) {
- if(money.compareAndSet(m, m+20,timestamp,timestamp+1)) {
- System.out.println("余额小于20元,充值成功,余额:"+ money.getReference() + "元");
- break;
- } else {
- break;
- }
- }
- }
- }
- };
- }.start();
- }
- new Thread() {
- public void run() {
- for (int j = 0; j < 100; j++) {
- while(true) {
- int timestamp = money.getStamp();
- Integer m = money.getReference();
- if(m>10) {
- System.out.println("大于10元");
- if(money.compareAndSet(m, m-10,timestamp,timestamp+1)) {
- System.out.println("成功消费10元,余额:" + money.getReference());
- break;
- }
- } else {
- System.out.println("没有足够金额");
- break;
- }
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- // TODO: handle exception
- }
- }
- };
- }.start();
- }
- }
5. AtomicIntegerArray
- //获得数组第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)
6. AtomicIntegerFieldUpdater
主要方法:
AtomicIntegerFieldUpdater.newUpdater()
incrementAndGet()
1.
Updater只能修改它可见范围内的变量。因为Updater使用反射得到这个变量。如果变量不可见,就会出错。比如如果score申明为private,就是不可行的。
2.
为了确保变量被正确的读取,它必须是volatile类型的。如果我们原有代码中未申明这个类型,那么简单得申明一下就行,这不会引起什么问题。
6
3. 由于CAS操作会通过对象实例中的偏移量直接进行赋值,因此,它不支持static字段(Unsafe.objectFieldOffset()不支持静态变量)。
使用用例:
- public class AtomicIntegerFieldUpdaterDemo {
- public static class Candidate {
- int id;
- volatile int score;
- }
- public final static AtomicIntegerFieldUpdater<Candidate> scoreUpdater
- = AtomicIntegerFieldUpdater.newUpdater(Candidate.class, "score");
- public static AtomicInteger allScore = new AtomicInteger(0);
- public static void main(String[] args) throws InterruptedException {
- final Candidate stu = new Candidate();
- Thread[] t = new Thread[10000];
- for(int i=0; i<10000; i++) {
- t[i] = new Thread() {
- @Override
- public void run() {
- if(Math.random() > 0.4) {
- scoreUpdater.incrementAndGet(stu);
- allScore.incrementAndGet();
- }
- }
- };
- t[i].start();
- }
- for(int i=0; i<10000; i++) {t[i].join();}
- System.out.println("score=" + stu.score);
- System.out.println("allScore=" + allScore);
- }
- }