atomic 保证原子性操作的包位于 java.util.concurrent 下。
image.png

Atomic 包相关类使用

AtomicReference

保证原子性的类引用对象,但是无法避免 CAS 的 ABA 问题。

测试案例

  1. package com.personal.test.atomic;
  2. import lombok.Data;
  3. import java.util.concurrent.atomic.AtomicReference;
  4. public class Atomic20201223171556 {
  5. public static void main(String[] args) {
  6. User u1 = new User("zhangsan", "1234#qwer");
  7. User u2 = new User("lisi", "1234#qwer");
  8. User u3 = new User("wangwu", "1234#qwer");
  9. User u5 = new User("zhangsan", "1234#qwer");
  10. // 声明
  11. AtomicReference<User> atomicReference = new AtomicReference<>(u1);
  12. // 比较期望值并且替换
  13. System.out.println(atomicReference.compareAndSet(u5, u2));
  14. // 比较期望值并且替换
  15. System.out.println(atomicReference.compareAndSet(u2, u3));
  16. System.out.println(atomicReference.get());
  17. }
  18. }
  19. @Data
  20. class User {
  21. private String username;
  22. private String password;
  23. public User(String username, String password) {
  24. this.username = username;
  25. this.password = password;
  26. }
  27. }

AtomicStampedReference

该对象能够解决 CAS 算法的 ABA 问题。

测试案例

  1. package com.personal.test.atomic;
  2. import java.util.concurrent.atomic.AtomicStampedReference;
  3. public class Atomic20201226231324 {
  4. public static void main(String[] args) {
  5. User u1 = new User("zhangsan", "1234#qwer");
  6. User u2 = new User("lisi", "1234#qwer");
  7. User u3 = new User("wangwu", "1234#qwer");
  8. User u5 = new User("zhangsan", "1234#qwer");
  9. // 声明
  10. AtomicStampedReference<User> atomicReference = new AtomicStampedReference<>(u1, 0);
  11. // 比较期望值并且替换
  12. System.out.println(atomicReference.compareAndSet(u1, u2, 0, 1));
  13. // 比较期望值并且替换
  14. System.out.println(atomicReference.compareAndSet(u2, u3, 1, 2));
  15. System.out.println(atomicReference.getStamp());
  16. System.out.println(atomicReference.getReference());
  17. }
  18. }

CAS 算法

一个线程失败或挂起并不会导致其他线程也失败或挂起,那么这种算法就被称为非阻塞算法。而CAS就是一种非阻塞算法实现,也是一种乐观锁技术,它能在不使用锁的情况下实现多线程安全,所以CAS也是一种无锁算法。

CAS JUC 原子变量 Atomic - 图2 比较并交换,是一种实现并发算法时常用到的技术,Java 并发包中的很多类都使用了 CAS 技术。

自旋锁

根据对象对应访问内存的值和本地线程内存的值,来确定是否一致,判断期间是否有其他线程进行修改。

CAS 缺点

主要存在两大缺点,
其一是 UnSafe 类中自旋耗时比较久,多线程环境下根据线程数的数量成正比时间增长。
其二是 ABA 问题,如果没有类似乐观锁等版本控制,可能存在中间操作导致其他问题。

Unsafe 是位于 sun.misc 包下的一个类。Unsafe 提供的 API 大致可分为内存操作、CAS、Class 相关、对象操作、线程调度、系统信息获取、内存屏障、数组操作等几类。由于并发相关的源码很多用到了 CAS,比如 java.util.concurrent.atomic 相关类、AQS、CurrentHashMap 等相关类。

参考资料

Unsafe 中 CAS 的实现
CAS 算法详解