原子操作
2021-02-15 本文已影响0人
ythmilk
无锁
通过CAS+volatile来实现
while (true) {
int prev = balance.get();
int next = prev - amount;
if (balance.compareAndSet(prev, next)) {
break;
}
}
// 可以简化为下面的方法
// balance.addAndGet(-1 * amount);
CAS特点
- 基于乐观锁设计,不怕修改共享变量,修改了也没事,继续等待就可以。
- synchronized是基于悲观锁,锁住操作,会导致线程状态切换,也会用户态到内核态切换。效率较差。
- CAS需要重试,CPU空转,如果是单核cpu或者线程数量大于cpu核心数,也会导致线程状态一直切换,效率反而变低。
CAS+volatile
cas+volatitle组合实现乐观锁,volatile只能保证可见性,和一部分的有序性,并不能防止指令重排序。通过cas+volatitle的组合实现乐观锁。
JUC中的原子类
原子整数
基本的i++,i--,等操作,还可以是表达式,表达式可以保证是原子操作。
AtomicBoolean
AtomicInteger
AtomicLong
原子引用
通过无锁的方式更新变量对象的引用值。
AtomicReference//不能解决ABA问题
AtomicStampedReference//增加版本号,可以追踪每次修改
AtomicMarkableReference//增加标识,可以看到是否修改,但不追踪整个过程
原子数组
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
字段更新器
线程安全的方式更新对象中的某个字段
需要配合volatitle使用:字段必须是volatile修饰的,否则抛出异常
AtomicReferenceFieldUpdater
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
原子累加器
性能更好
Unsafe
Unsafe 对象提供了非常底层的,操作内存、线程的方法,Unsafe 对象不能直接调用,只能通过反射获得
Unsafe实现CAS
class Student {
volatile int id;
volatile String name; }
Unsafe unsafe = UnsafeAccessor.getUnsafe();
Field id = Student.class.getDeclaredField("id");
Field name = Student.class.getDeclaredField("name");
// 获得成员变量的偏移量
long idOffset = UnsafeAccessor.unsafe.objectFieldOffset(id);
long nameOffset = UnsafeAccessor.unsafe.objectFieldOffset(name);
Student student = new Student();
// 使用 cas 方法替换成员变量的值
UnsafeAccessor.unsafe.compareAndSwapInt(student, idOffset, 0, 20); // 返回 true
UnsafeAccessor.unsafe.compareAndSwapObject(student, nameOffset, null, "张三"); // 返回 true
System.out.println(student);