原子操作

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特点

  1. 基于乐观锁设计,不怕修改共享变量,修改了也没事,继续等待就可以。
  2. synchronized是基于悲观锁,锁住操作,会导致线程状态切换,也会用户态到内核态切换。效率较差。
  3. 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);
上一篇 下一篇

猜你喜欢

热点阅读