众所周知,i++分为三步:
1. 读取i的值
2. 计算i+1
3. 将计算出i+1赋给i
可以使用锁来保持操作的原子性,用volatile保持值的可见性和操作顺序性;
如果仅仅是计算操作,我们自然就想到了java.util.concurrent.atomic包下的原子类,则不必考虑锁的升级、获取、释放等消耗,也不必考虑锁的粒度、种类、可重入性等;
下面来看下AtomicInteger的incrementAndGet方法源码:
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; }
incrementAndGet,先increment,再get,所以获取的是increment后的值,而unsafe.getAndAddInt先get,所以这里需要"+1";
那这里的valueOffset又是什么呢?
private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }
AtomicInteger的静态属性valueOffset,属性value的偏移量,在类加载的时候,通过AtomicInteger的Field——"value"初始化,后续通过当前的AtomicInteger实例和该valueOffset obtain该实例value属性的值;
unsafe.getAndAddInt IDEA反编译后源码如下:
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
unsafe.getAndAddInt具体实现是不停的compare主存中取到的值var5和当前的线程的工作内存中的值(通过对象var1和偏移量var2获得),直到两者equal则更新为新值var5+var4(delta) ,从这里我们也体会到了Java内存模型。
getIntVolatile(主存)和compareAndSwapInt都是sun.misc.Unsafe的native方法。
下面是一个小例子,分别是非线程安全的i++,锁同步以及Atomic Class:
public class Counter { @Getter private volatile int i = 0; @Getter private volatile AtomicInteger atomicInteger = new AtomicInteger(0); public void increment(){ i++; // 1. 读取i的值 // 2. 计算i+1 // 3. 把i+1的值赋给i } public void incrementSync(){ synchronized(this) { i++; // 1. 读取i的值 // 2. 计算i+1 // 3. 把i+1的值赋给i } } public void incrementAtomic(){ // 先increment再返回 atomicInteger.incrementAndGet(); } }
测试类:
public class AtomicityTest { private Counter counter; /** * 每个线程打印的次数 */ private int count; @Before public void init(){ counter = new Counter(); count = 10000; } /** * 非线程安全的i++ */ @Test public void increment() throws InterruptedException { Thread t1 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.increment(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.increment(); } }); t1.start(); t2.start(); // 单元测试必须新起的线程要在主线程里join,否则主线程运行完毕,新起的线程还执行完 t1.join(); t2.join(); /* ThreeParamsEquals<Enum, Enum, Enum> equals = (Enum p1, Enum p2, Enum p3) -> p1.equals(p2) && p1.equals(p3); while (true){ if (equals.equals(Thread.State.TERMINATED, t1.getState(), t2.getState())) { break; } }*/ System.out.println(t1.getState()); System.out.println(t2.getState()); // 由于不是原子性操作,两个线程执行总共20000次i++,结果i的值都小于20000 System.out.println(counter.getI()); } /** * 线程安全的i++ */ @Test public void incrementSync() throws InterruptedException { Thread t1 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.incrementSync(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.incrementSync(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(t1.getState()); System.out.println(t2.getState()); // 由于保证了原子性,顺序性,可见性操作,两个线程执行总共20000次i++,结果i的值都等于20000 System.out.println(counter.getI()); } /** * 原子类AtomicInteger */ @Test public void incrementAtomic() throws InterruptedException { Thread t1 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.incrementAtomic(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < count; i++) { counter.incrementAtomic(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(t1.getState()); System.out.println(t2.getState()); // 由于保证了原子性,顺序性,可见性操作,两个线程执行总共20000次i++,结果i的值都等于20000 System.out.println(counter.getAtomicInteger()); } }
原文地址:https://www.cnblogs.com/theRhyme/p/12129120.html