「java.util.concurrent并发包」之 Atomic
Atomic 翻译成中文是原子的意思。在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的。在我们这里 Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。
所以,所谓原子类说简单点就是具有原子/原子操作特征的类。
以 AtomicInteger 为例子来介绍。
AtomicInteger 类常用方法
public final int get() //获取当前的值 public final int getAndSet(int newValue)//获取当前的值,并设置新的值 public final int getAndIncrement()//获取当前的值,并自增 public final int getAndDecrement() //获取当前的值,并自减 public final int getAndAdd(int delta) //获取当前的值,并加上预期的值 boolean compareAndSet(int expect, int update) //如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update) public final void lazySet(int newValue)//最终设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
基本数据类型原子类的优势
通过一个简单例子带大家看一下基本数据类型原子类的优势
1、多线程环境不使用原子类保证线程安全(基本数据类型)
class Test { private volatile int count = 0; //若要线程安全执行执行count++,需要加锁 public synchronized void increment() { count++; } public int getCount() { return count; } }
2、多线程环境使用原子类保证线程安全(基本数据类型)
class Test2 { private AtomicInteger count = new AtomicInteger(); public void increment() { count.incrementAndGet(); } //使用AtomicInteger之后,不需要加锁,也可以实现线程安全。 public int getCount() { return count.get(); } }
AtomicInteger 线程安全原理简单分析
AtomicInteger 类的部分源码:
// setup to use Unsafe.compareAndSwapInt for updates(更新操作时提供“比较并替换”的作用) 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;
AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升。
CAS 的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个 volatile 变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。