1)原子整数类:AtomicInt AtomicLong AtomicBoolean

下面以AtomicLong为例,贴一些用法:

  1. // 这里的value代表初始值 不传入则默认0L
  2. AtomicLong al = new AtomicLong(value);
  3. long res = al.get(); // 获取value值
  4. long res = al.incrementAndGet(); // 相当于非原子的++value
  5. long res = al.decrementAndGet(); // 相当于非原子的--value
  6. long res = al.addAndGet(long v); // 相当于 res = value+v
  7. long res = al.updateAndGet(value -> value*6); // 自定义计算

2)原子引用类:AtomicReference AtomicStampedReference AtomicMarkableReference

  1. // 代表创建了一个存储String类型的原子引用对象 初始值为a
  2. AtomicReference<String> ar = new AtomicReference<>("a");
  3. ar.getAndSet("b"); // 将a改成b
  4. ar.getAndUpdate(value -> value + "c"); // 把b变成bc

注意这里会导致ABA问题,也即是说,这里判断的只是值是否相等,如果相等就执行设置值,假设现在线程1获取到初始值为A,之后准备进行CAS操作,这时线程2将A修改成B,之后又修改回A,对于线程1来说,它判断到值还是A会正常设置值,但实际上这里的A已经不是原来那个A了。

对于大多数情况下,ABA问题都不会造成业务问题,如果想避免ABA问题,可以使用后面那两个类,第一个 AtomicStampedReference 其实就是打上一个整型的戳号,后续每次进行CAS都对戳号加一处理,这里关心的是被修改过多少次;第二个 AtomicMarkableReference 就是加上一个mark标记,这里关注的是有没有被修改过。

3)原子数组类:AtomicIntegerArray AtomicLongArray AtomicReferenceArray

如果我们要修改的不是引用本身的值,而是想修改引用的对象的值,就可以使用这些类,例如我们可以使用这些类来对数组的指定下标的元素进行修改,修改的方法和上面的类似,只是多了个传参下标,这里不记录了。