Java并发编程札记-(三)JUC原子类-02原子方式更新单个变量

今天学习AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference,这几个类的共同特点是都提供单个变量的原子方式访问和更新功能。下面以AtomicLong为代表,对这些类进行介绍。

AtomicLong可以看做是用原子方式更新的long值,实例提供long类型单个变量的原子方式访问和更新功能。

API

//构造方法摘要
        AtomicLong() 
          //创建具有初始值0的新AtomicLong。
        AtomicLong(long initialValue) 
          //创建具有给定初始值的新AtomicLong。
//方法摘要
long    addAndGet(long delta)
         //以原子方式将给定值添加到当前值。
boolean compareAndSet(long expect, long update)
         //如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
long    decrementAndGet()
         //以原子方式将当前值减 1。
double  doubleValue()
         //以 double 形式返回指定的数值。
float   floatValue()
         //以 float 形式返回指定的数值。
long    get()
         //获取当前值。
long    getAndAdd(long delta)
         //以原子方式将给定值添加到当前值。
long    getAndDecrement()
         //以原子方式将当前值减 1。
long    getAndIncrement()
         //以原子方式将当前值加 1。
long    getAndSet(long newValue)
         //以原子方式设置为给定值,并返回旧值。
long    incrementAndGet()
         //以原子方式将当前值加 1。
int     intValue()
         //以 int 形式返回指定的数值。
void    lazySet(long newValue)
         //最后设置为给定值。
long    longValue()
         //以 long 形式返回指定的数值。
void    set(long newValue)
         //设置为给定值。
String  toString()
         //返回当前值的字符串表示形式。
boolean weakCompareAndSet(long expect, long update)
         //如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。
long    getAndUpdate(LongUnaryOperator updateFunction)
         //将当前值以原子方式更新为updateFunction方法的结果,并返回更新前的值
long    updateAndGet(LongUnaryOperator updateFunction)
         //将当前值以原子方式更新为updateFunction方法的结果,并返回更新后的值
long    getAndAccumulate(long x,LongBinaryOperator accumulatorFunction)
         //将当前值以原子方式更新为updateFunction方法的结果(方法参数为x和当前值),并返回更新前的值
long    accumulateAndGet(long x,LongBinaryOperator accumulatorFunction)
         //将当前值以原子方式更新为updateFunction方法的结果(方法参数为x和当前值),并返回更新后的值

例1:long型变量的原子访问和更新

通常情况下,在Java中的++i或者–i不是线程安全的。一般情况下,只能加锁才能保证上述操作的原子性。有了AtomicLong后,使用AtomicLong就可以保证上述操作的原子性。

Counter是一个计数器类。

class Counter extends Thread {
    private static long counter = 0;

    public static long addOne() {
        return ++counter;
    }
}

在多线程环境下测试其是否可用。

public class AtomicLongDemo {

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread() {
                public void run() {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (Counter.addOne() == 100) {
                        System.out.println("计数器值最终值为100");
                    }
                }
            };
            thread.start();
        }
    }
}

测试程序在连续运行100次++counter后,判断计数器值是否为100,如果为100就打印计数器值最终值为100,否则就什么都不打印。
数次运行程序后,发现大多数结果是什么都没有打印,说明次计数器在多线程环境下不可用。
修改计数器类。

import java.util.concurrent.atomic.AtomicLong;

class Counter {
    private static AtomicLong counter = new AtomicLong(0);

    public static long addOne() {
        return counter.incrementAndGet();
    }
}

数次运行程序后,发现结果全部为计数器值最终值为100

实现原理

以incrementAndGet()为例,看看AtomicLong如何实现单个变量的原子方式更新功能。

private static final Unsafe unsafe = Unsafe.getUnsafe();
static {
    try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicLong.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}
public final long incrementAndGet() {
    return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
}

Unsafe是CAS的核心类。可以看出AtomicLong是基于CAS实现的。

AtomicBoolean、AtomicInteger、AtomicReference与AtomicLong很相似,就不多做介绍了。

本文就讲到这里,想了解Java并发编程更多内容请参考:

  • Java并发编程札记-目录

END.

你可能感兴趣的:(Java并发,Java并发编程札记)