线程安全之原子性操作

一、原子性操作方法

1.1 同步锁

 synchronized (this){
   ++ count;
}

1.2 Atomic类

  • Atomic底层利用CAS实现,而CAS则是利用UnSafe类(native) + 反射技术实现,通过do...while(自旋)的模式,每次都会检查变量是否被修改过,修改过则while成立并重做。
private AtomicLong acount = new AtomicLong(0L);
acount.incrementAndGet();

1.3 LongAdder类

  • LongAdder为JDK8提供的多线程技术类,底层是利用分而治之的思想,即为每个线程分配一个计数副本,线程之间的副本相互隔离,最终将所有副本相加,多线程下计数速度最快。
private LongAdder lacount = new LongAdder();
// 计数
lacount.increment();
// 获取结果
lacount.sum()

 

二、Atomic类实现原理-CAS

    1. 通过Unsafe获取对象属性偏移量
    1. 利用UnsafeCMS方法及获取到的偏移量实现自增(操作内存)
public class LockDemo1 {
    private volatile int value = 0;
    // 直接操作内存,修改对象、数组内存等
    private static Unsafe unsafe;
    // 获取属性偏移量
    private static long valueOfferset;

    static {
        try {
            //反射技术获取unsafe值
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe)field.get(null);

            // 获取到value属性偏移量(用于定位value属性在内存中的具体地址)
            valueOfferset = unsafe.objectFieldOffset(LockDemo1.class.getDeclaredField("value"));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }

    }

    public void add() {
        // i++; 在Java层面分为三个步骤
        // CAS + 循环重试(自旋)
        int current;
        do {
            // 操作耗时的话线程会占用大量的CPU执行时间
            current = unsafe.getIntVolatile(this, valueOfferset);
        } while (!unsafe.compareAndSwapInt(this, valueOfferset, current, current + 1));
        // 执行失败则重试
    }

    public static void main(String[] args) throws InterruptedException {
        LockDemo1 lockDemo1 = new LockDemo1();

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    lockDemo1.add();
                }
            }).start();
        }
        Thread.sleep(2000L);
        System.out.println(lockDemo1.value);
    }
}