原子类是对volatlie的补充,利用cas原理达到操作不可分割保证原子性,在多线程下粒度细,效率高,可以把锁定位在变量的级别,但是在高度竞争下效率不如锁。AtomicInteger可以对一个int进行原子更新AtomicInteger不能用作Integer的替代品 。但是可以利用工具对数值在多线程下的原子操作
源码分析
重要属性
//原子类底层真正的值,volatile修饰能保证可见性和禁止指令重排序
private volatile int value;
构造方法
//构造方法
/**
* 构造一个原子类默认就是value初始值也就是0
*/
public AtomicInteger() {
}
/**
* 创造一个原子类对象,值为传入的初始值initialValue
*
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
方法分析
原子类提供了一些常用方法,其中也提供了普通的操作方法,这些方法不能保证线程安全,故不重要,违背了原子类设计的思想
/**
* 返回原子类的值,并没加额外的线程安全措施
*
*/
public final int get() {
return value;
}
/**
* 设置原子类的值,并没加额外的线程安全措施
*
* @param newValue the new value
*/
public final void set(int newValue) {
value = newValue;
}
下面是原子类符合设计初衷的方法,能对数值进行原子操作,底层利用的是CAS算法实现的,保证线程安全
/**
* 用给定的值跟新旧的值,返回旧值
*
*/
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
/**
* 如果当前值为 ==为预期值,则将该值原子设置为给定的更新值。
*在多线程下会发生自旋,并发度高的情况下反而影响效率消耗资源
*true如果成功。 False return表示实际值不等于预期值。不跟新
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
}
/**
* 原子上增加一个当前值。返回旧值
*
* @return the previous value
*/
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
/**
* 原子上减小一个当前值。返回旧值
*
*/
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
/**
* 原子上增加给定的值。返回旧值
*
*/
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
/**
* 原子上增加一个值。返回新值
*
* @return the updated value
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
/**
* 原子上较少一个值。返回新值
*
* @return the updated value
*/
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
原理分析
private static final Unsafe unsafe = Unsafe.getUnsafe();这个类对象调用方法能原子操作,利用的是CAS原理,底层我就不粘贴了,因为我发现这个类的源码我打不开,下面对CAS原理分析看代码
public class S {
static int expectedValue;
public static void main(String[] args) throws InterruptedException {
compareAndSet(0, 1);
}
private static int compareAndSet(int a, int b) {
//判断预期值
if (expectedValue == a ) {
//如果等于预期值就更新
expectedValue = b;
}else {
//否则返回原来的值
return expectedValue;
}
return expectedValue;
}
}
以上就是模拟CAS原理,原子类在进行操作时,会拿着期望值和旧的值比较,如过相等就用新的值代替旧的值,如果不想等说明有人更改了,就自旋更新新的期望值,在去做重复比较,直到成功,这样就能保证原子性
案例
public class S {
//原子整形,利用CAS原理保证原子性
static AtomicInteger a=new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new VoDemo());
Thread thread1 = new Thread(new VoDemo());
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(a);
}
static class VoDemo implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
a.incrementAndGet();
}
}
}
}
发现两个线程同时执行共20000次结果为20000,如果改成普通int,在线程里面a++发现每次结果都是大概14000左右