Java 中的原子类主要分为以下 4 组,共 13 个:
基本类型原子类:包括AtomicInteger、AtomicLong、AtomicBoolean。它们分别用于对int、long、boolean类型的变量进行原子操作,提供了如get()、set()、incrementAndGet()、decrementAndGet()等方法,方便在多线程环境下对基本数据类型进行安全的操作,适用于简单的计数器、标志位等场景。
数组类型原子类:有AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。用于对数组中的元素进行原子操作,通过索引来访问和修改数组中的元素,保证了在多线程环境下对数组操作的线程安全性,适用于需要对数组进行并发更新的场景,如多个线程同时更新一个数组中的不同元素。
引用类型原子类:如AtomicReference、AtomicStampedReference、AtomicMarkableReference。AtomicReference用于对对象引用进行原子操作,可以保证对象引用的更新是原子性的,适用于需要在多线程环境下共享对象且保证对象引用更新安全的场景。AtomicStampedReference和AtomicMarkableReference则是在AtomicReference的基础上解决了 ABA 问题,分别通过添加版本号和标记位的方式来确保对对象引用操作的正确性。
对象属性原子类:包括AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater。用于对对象的某个属性进行原子性更新,通过反射机制来获取和更新对象的指定属性,适用于无法直接使用原子类包装对象属性,但又需要对其进行原子操作的场景,如对已有的对象结构中的某个属性进行并发更新。
1.原子整数
J.U.C并发包提供了AtomicBoolean,AtomicInteger,AtomicLong。
1.1 AtomicInteger
1.1.1
api:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicInteger.html
方法都是原子的,利用CAS保证了线程安全。
举例:
incrementAndGet():自增,相当于++i
getAndAdd(int delta):相当于获取这个数,并加delta。
1.1.2 updateAndGet
还有getAndUpdate,这里以updateAndGet(先计算,后获取值)为例。
介绍
使用例子:
AtomicInteger i=new AtomicInteger(5);
i.updateAndGet(value->value*10);
System.out.println(i.get());//返回50
//------------读取到->设置值------------
原理
循环进行CAS操作,直至成功。
1.1.3 其他类型的原子更新
2.原子引用
AtomicReference,AtomicStampedReference,AtomicMarkableReference。
2.1 AtomicReference
2.1.1 使用
举例如下
2.1.2 ABA问题
解决办法见2.2
2.2 AtomicStampedReference
特点:加版本号
使用
举例
2.3 AtomicMarkableReference
特点:不需要记录版本号,只需要记录是否更改过
具体可以看看这篇博客:http://www.nituchao.com/juc-atomic/24.html
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedMark,
int newMark) ;
public void set(V newReference, int newMark);
3.原子数组
4.原子更新字段类
如果需原子地更新某个类里的某个字段时,就需要使用原子更新字段类。
要想原子地更新字段类需要两步。第一步,因为原子更新字段类都是抽象类,每次使用的 时候必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。第 二步,更新类的字段(属性)必须使用public volatile修饰符。
举例:
5.Unsafe
概述
Unsafe对象提供了底层的,操作内存、线程的方法,Unsafe对象不能直接调用,只能通过反射获得。
前面的原子操作类的很多方法实际是调用了UnSafe中的方法。
CAS
使用示例:给id赋值