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. AtomicStampedReference
a. 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);
-
}
-
}