前言
我们知道i++操作实际上是线程不安全的,因为一个i++操作分为了三步:
- 1、获取的i的值
- 2、执行i+1
- 3、将i+1的结果赋值给i
而这三步不是一个原子操作,多线程环境下就会出现线程不安全性问题。
Java从JDK 1.5开始,在
java.util.concurrent.atomic包下提供了12个对应的原子类操作,让我们可以直接使用原子操作类来实现一个原子的i++操作。
Java中一共提供了12个原子类操作,可以分为四种类型,分别是:
- 原子更新基本类型
- 原子更新数组
- 原子更新引用
- 原子更新属性
下面就让我们一起来看看这四大类中的12个原子操作类:
原子更新基本类型
原子更新基本数据类型有以下三个:
- AtomicInteger:原子更新整型。
- AtomicBoolean:原子更新布尔类型。
- AtomicLong:原子更新长整型。
AtomicInteger
常用方法如下:
- int addAndGet(int delta):
以原子方式将传入的数值与实例中的值(AtomicInteger里的 value)相加,并返回结果。 - boolean compareAndSet(int expect,int update):
如果输入的数值等于预期值,则以原子方式将该值设置为输入的值,成功返回true,替换失败则返回false - int getAndIncrement():
以原子方式将当前值自增1,并返回自增前的值。 - int getAndDecrement():
以原子方式将当前值自减1,并返回自减前的值。 - void lazySet(int newValue):
最终会设置成 newValue,注意这个方法是一个lazy方法,也就是说设置之后,并不会马上去将值更新到主内存,那么其他线程在一小段时间内可能看不到设置的值。 - int getAndSet(int newValue):
以原子方式将值设置为newValue,并返回旧值。
代码示例
package com.zwx.concurrent.atomic;
import java.util.concurrent.atomic.AtomicInteger;
public class TestAtomicBasicData {
public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicInteger = new AtomicInteger(8);
System.out.println("初始化:" + atomicInteger);//8
atomicInteger.compareAndSet(8,10);
System.out.println("CAS后:" + atomicInteger);//10
System.out.println(atomicInteger.getAndIncrement());//自增1,返回自增前的值10
System.out.println("自增后:" + atomicInteger);//11
System.out.println(atomicInteger.getAndDecrement());//11
System.out.println("自减后:" + atomicInteger);//10
}
}
AtomicBoolean
更新boolean值,常用方法如下:
- boolean compareAndSet(boolean expect,boolean update):
如果输入的数值等于预期值,则以原子方式将该值设置为输入的值,成功返回true,替换失败则返回false。注意这里面实际上会先将boolean值转换为int类型,0-否 1-是 - void lazySet(boolan newValue):
最终会设置成 newValue,注意这个方法是一个lazy方法,也就是说设置之后,并不会马上去将值更新到主内存,那么其他线程在一小段时间内可能看不到设置的值。 - boolean getAndSet(boolean newValue):
以原子方式将值设置为newValue,并返回旧值。
AtomicLong
这个和上面的AtomicInteger几乎是一样的,就不在举例了。
原子操作都是利用Unsafe类中的CAS操作实现的,但是Unsafe中只提供了三种类型的CAS操作: