1.原子整数
* AtomicBoolean
* AtomicInteger
* AtomicLong
以AtomicInteger为例:
public class test {
public static void main(String[] args) throws InterruptedException {
AtomicInteger i = new AtomicInteger(0);
//获取并自增(i= 0,结果i = 1,返回0),类似于i++
System.out.println(i.getAndIncrement());
//自增并获取(i = 1,结果 i =2;返回2);类似于 ++i
System.out.println(i.incrementAndGet());
//自减并获取(i=2,结果 i = 1,返回 1 ),类似于--i
System.out.println(i.decrementAndGet());
//获取并自减(i=1,结果 i = 0,返回 1 ),类似于i--
System.out.println(i.getAndDecrement());
//获取并加值(i=0,结果i=5,返回0),类似于 i += 5;
System.out.println(i.getAndAdd(5));
i.updateAndGet(new IntUnaryOperator() {
@Override
public int applyAsInt(int value) {
value = value*10;
return value;
}
});
}
}
2.原子引用
* AtomicReference
* AtomicMarkableReference
* AtomicStampedReference
public class test {
public static void main(String[] args) throws InterruptedException {
DecimalAccount.demo(new DecimalAccountCas(new BigDecimal("10000")));
}
}
class DecimalAccountCas implements DecimalAccount{
private AtomicReference<BigDecimal> balance; //范型中就是要保护的类型
public DecimalAccountCas(BigDecimal balance) {
this.balance = new AtomicReference<>(balance);
}
@Override
public BigDecimal getBalance() {
return balance.get();
}
@Override
public void withdraw(BigDecimal amount) {
while (true){
BigDecimal pre = balance.get();
BigDecimal next = pre.subtract(amount); //减去amount
if (balance.compareAndSet(pre,next)){
break;
}
}
}
}
interface DecimalAccount{
//获取余额
BigDecimal getBalance();
//取款
void withdraw(BigDecimal amount);
/*
* 方法内会启动1000个线程,每个线程做 -10元操作,
* 如果初始余额为10000 那么正确的结果为0
* */
static void demo(DecimalAccount account){
ArrayList<Thread> ts = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
ts.add(new Thread(() -> {
account.withdraw(BigDecimal.TEN);
}));
}
ts.forEach(Thread :: start);
ts.forEach(t -> {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(account.getBalance());
}
}
AtomicStampedReference
AtomicReference会有一个问题(cas),cas会有ABA问题。
所以AtomicStampedReference就多了一个版本号来解决这个问题。
AtomicStampedReference可以给原子引用加上版本号,追踪原子引用整个的变化过程,如:A -> B -> A -> C,通过AtomicStampedReference,我们可以知道引用变量中途被更改了几次。
但是有时候,并不关心引用变量更改了几次,只是单纯的关心是否更改过,所以就有了AtomicMarkableReference
AtomicMarkableReference![](https://i-blog.csdnimg.cn/blog_migrate/ac462ec44c612e29c056cc2199d9426d.png)
3.原子数组
之前的原子引用保护的是多个线程对一个对象引用进行修改时的线程安全性。像之前的
ref这个保护的是BigDecimal,
这里获取新的值,和变化以后的值。最后ref调用compeareAndSet变化的引用本身,变化成功就是next那个引用。
但是有时候我们有时候并不是想修改引用本身而是想修改对象里面的内容,例如:数组(要对数组里面的元素保证线程安全)
* AtomicIntegerArray(保护的数组里面元素是整型的)
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);
* AtomicLongArray(保护的数组里面元素是长整型的)
* AtomicReferenceArray(保护的数组里面元素是引用类型的)
4.原子字段更新器
* AtomicReferenceFieldUpdater //保护的是对象里面某个引用类型的字段
* AtomicIntegerFieldUpdater
* AtomicLongFieldUpdater
5.原子累加器
AtomicInteger做累加的效率没有AtomicAdder的高。
即AtomicInteger对一个变量累加,而AtomicAdder是对多个变量累加。