「java.util.concurrent并发包1」之 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可以保证任何时刻任何线程总能拿到该变量的最新值。