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

时间:2022-05-01 18:01:22

今天学习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并发编程更多内容请参考:

END.