Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。

1. 分类:

1.1 基本类型

1.1.1 AtomicInteger 整型原子类

常见用法:

  1. /**
  2. * 此方法是AtomicInteger原子类的测试类
  3. */
  4. public class AtomicIntegerTest {
  5. public static void main(String[] args) {
  6. AtomicInteger num = new AtomicInteger(10);
  7. /**
  8. * 获取当前值
  9. */
  10. int n1 = num.get();
  11. System.out.println("n1 --> " + n1 + " and now num --> " + num);
  12. /**
  13. * 获取当前值 并设置新的值
  14. */
  15. int n2 = num.getAndSet(20);
  16. System.out.println("n2 --> " + n2 + " and now num --> " + num);
  17. /**
  18. * 获取当前值 并自增
  19. * n3 --> 20 and now num --> 21
  20. */
  21. //int n3 = num.getAndIncrement();
  22. int n3 = num.incrementAndGet();
  23. System.out.println("n3 --> " + n3 + " and now num --> " + num);
  24. /**
  25. * 获取当前值 并自减
  26. */
  27. int n4 = num.getAndDecrement();
  28. System.out.println("n4 --> " + n4 + " and now num --> " + num);
  29. /**
  30. * 获取当前值 并加相应值
  31. */
  32. int n5 = num.getAndAdd(10);
  33. System.out.println("n5 --> " + n5 + " and now num --> " + num);
  34. /**
  35. * 如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)
  36. */
  37. boolean b = num.compareAndSet(30, 5);
  38. System.out.println("b --> " + b + " and now num --> " + num);
  39. }
  40. }
  41. // ---结果------
  42. n1 --> 10 and now num --> 10
  43. n2 --> 10 and now num --> 20
  44. n3 --> 21 and now num --> 21
  45. n4 --> 21 and now num --> 20
  46. n5 --> 20 and now num --> 30
  47. b --> true and now num --> 5

多线程环境保证线程安全:

// volatile + synchronized 结合保证线程安全
public class MutiThreadDemo {
    /**
     * volatile关键字表示 线程间共享
     */
    private volatile int count = 0;

    /**
     * 方法上锁
     */
    public synchronized void increamentCount() {
        count++;
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        MutiThreadDemo counter = new MutiThreadDemo();
        int workCount = 50000;
        ExecutorService executor = Executors.newFixedThreadPool(10);
        long start = System.currentTimeMillis();
        for (int i = 0; i < workCount; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    counter.increamentCount();
                }
            };
            executor.execute(runnable);
        }
        // 关闭启动线程,执行未完成的任务
        executor.shutdown();
        // 等待所有线程完成任务,完成后才继续执行下一步
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
        System.out.println("执行结果:count=" + counter.getCount());
    }
}
// ----------------------------------
/**
 * 多线程环境下使用AtomicInter原子类
 */
public class MutiThreadUseAtomicDemo {
    private AtomicInteger count = new AtomicInteger();

    public void increamentCount() {
        count.incrementAndGet();
    }

    public int getCount() {
        return count.get();
    }

    public static void main(String[] args) throws InterruptedException {
        MutiThreadUseAtomicDemo counter = new MutiThreadUseAtomicDemo();
        int workCount = 50000;
        ExecutorService executor = Executors.newFixedThreadPool(10);
        long start = System.currentTimeMillis();
        for (int i = 0; i < workCount; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    counter.increamentCount();
                }
            };
            executor.execute(runnable);
        }
        // 关闭启动线程,执行未完成的任务
        executor.shutdown();
        // 等待所有线程完成任务,完成后才继续执行下一步
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
        System.out.println("执行结果:count=" + counter.getCount());
    }
}

AtomicInteger线程安全原理分析:

AtomicInteger主要是利用CAS + volatile + native方法来保证原子操作的。
在AtomicInteger原子类中, getAndIncrement方法实际上调的是UnSafe类中的方法(Java中的Unsafe类为我们提供了类似C++手动管理内存的能力)
image.png
PS:
this —> AtomicInteger实例
unsafe —-> 后门类, 用于直接操作内存中的数据.
valueOffset —> 数据在内存中地址偏移量.
value —> 要修改的值, volatile保证了可见性
image.png
UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个volatile变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。
拿到对象的偏移量, 可以定位到在内存中的值, 接下来执行getAndAddInt方法.
image.png
参数1: 当前对象, 参数2: 对象的偏移量, 参数3:要增加的值。compareAndSwapInt使用原理是CAS。
image.png

AtomicLong 长整型原子类(同上)

AtomicBoolean 布尔型原子类

1.2 数组类型原子类

使用原子的方式更新数组里的某个元素

AtomicIntegerArray:整形数组原子类

/**
 * 整形数组原子类使用
 */
public class AtomicIntegerArrayTest {
    public static void main(String[] args) {
        int[] nums = {1,2,3,4,5,6};
        AtomicIntegerArray arrays = new AtomicIntegerArray(nums);
        for (int i = 0; i < arrays.length(); i++) {
            /**
             * 获取 index=i 位置元素的值
             */
            System.out.print(arrays.get(i) + " ");
        }
        System.out.println("\n---------------");
        /**
         * 返回 index=i 位置的当前的值,并将其设置为新值:newValue
         */
        int arr0 = arrays.getAndSet(0, 6);
        System.out.println("arr0 -> " + arr0 + " arrays[0] -> " + arrays.get(0));

        /**
         * 返回 index=i 位置的当前的值,并将其add值
         */
        int arr1 = arrays.getAndAdd(1, 6);
        System.out.println("arr1 -> " + arr1 + " arrays[1] -> " + arrays.get(1));

        /**
         * 返回 index=i 位置的当前的值,并将其+1
         */
        int arr2 = arrays.getAndIncrement(2);
        System.out.println("arr2 -> " + arr2 + " arrays[2] -> " + arrays.get(2));

        /**
         * 返回 index=i 位置的当前的值,并将其-1
         */
        int arr3 = arrays.getAndIncrement(3);
        System.out.println("arr3 -> " + arr3 + " arrays[3] -> " + arrays.get(3));

        boolean success = arrays.compareAndSet(4, 5, 10);
        System.out.println("success -> " + success + " arrays[4] -> " + arrays.get(4));
        for (int i = 0; i < arrays.length(); i++) {
            System.out.print(arrays.get(i) + " ");
        }
    }
}

AtomicLongArray:长整形数组原子类(同上)

AtomicReferenceArray :引用类型数组原子类(同上)

还有很多, 未完待续…