这三个属性
特征
是否可以不要锁定整个对象
减少锁定的范围
之 关注长期、敏感性变化的某一个字段表
而不是整个字段
以达到精确加锁和节约内存的目的
类似于微创手术
对一个对象的某个字段加锁
这个思想
要求
因为对象的属性修改类型原子类都是抽象类
所以每次使用都必须使用静态方法newUpdater()创建一个更新器
并且需要设置想要更新的类和属性
class Bank{
String name = "ccb";
// 以一种线程安全的方式操作非线程安全对象内的某些字段
// 1. 更新的对象属性必须使用public volatile修饰符
public volatile int money = 123 ;
/* 2. 因为对象的属性修改类型原子类都是抽象类
所以每次使用都必须使用静态方法newUpdater()创建一个更新器
并且需要设置想要更新的类和属性
*/
AtomicIntegerFieldUpdater atomicIntegerFieldUpdater=
AtomicIntegerFieldUpdater.newUpdater(Bank.class,"money");
// 3. 构造操作方法
public void transfer(Bank bank){
atomicIntegerFieldUpdater.incrementAndGet(bank);
}
}
原子更新引用类型的值 (重要)
class MyVar{
public volatile Boolean inInit = Boolean.FALSE;
// 原子更新引用类型的值
AtomicReferenceFieldUpdater<MyVar,Boolean> FieldUpdater=
AtomicReferenceFieldUpdater.newUpdater(MyVar.class,Boolean.class,"inInit");
// 初始化
public void init(MyVar myVar){
if(FieldUpdater.compareAndSet(myVar,Boolean.FALSE,Boolean.TRUE)){
System.out.println(Thread.currentThread().getName()+" 开始初始化");
// ---
System.out.println(Thread.currentThread().getName()+" 初始化完成");
}else{
System.out.println(Thread.currentThread().getName()+" 抢夺失败 已经有线程修改中");
}
}
}
流程图
使用compareAndSet方法检查并设置inInit的值。
如果当前值为FALSE,则设置为TRUE,表示开始初始化,并打印线程名称和初始化信息。
如果当前值不为FALSE,则表示已有线程在进行初始化,当前线程抢夺失败。
卖票案例 优化
以前的卖票
是多对一
多个线程操作同一个票 资源类
用 Synchronized 关键字
加一把重锁
使用AtomicReferenceFieldUpdater来实现线程安全的初始化逻辑,相比使用synchronized关键字有以下好处:
无锁机制:compareAndSet方法通过CAS(Compare-And-Swap)操作实现原子更新,不需要加锁,减少了线程阻塞和上下文切换的开销。
高并发性能:在高并发场景下,无锁机制可以显著提高吞吐量,因为多个线程不会因竞争锁而频繁阻塞。
细粒度控制:AtomicReferenceFieldUpdater只对特定字段进行原子操作,而synchronized会锁定整个对象或代码块,影响范围更大。
锁机制:
synchronized:基于锁的机制,线程需要等待获取锁才能执行临界区代码,可能导致阻塞。
AtomicReferenceFieldUpdater:基于CAS的无锁机制,线程直接尝试更新,只有冲突时才会重试,避免了阻塞。
性能:
synchronized:在高并发情况下,频繁的锁竞争会导致性能下降。
AtomicReferenceFieldUpdater:在大多数情况下,CAS操作非常高效,尤其适合读多写少的场景。
灵活性:
synchronized:锁定范围较大,可能影响其他不相关的操作。
AtomicReferenceFieldUpdater:仅对特定字段进行原子操作,不影响其他字段或方法。
通知型 敏感型的字段不要整体加锁
字段层面的原子性加锁
而不是锁整个对象
达到轻量级的原子操作
节省资源