对象的属性修改原子类的类型
AtomiclntegerFieldUpdater —— 原子更新对象中int类型字段的值
AtomicL ongFieldUpdater —— 原子更新对象中Long类型字段的值
AtomicReferenceFieldUpdater —— 原子更新引用类型字段的值
使用目的
以一种线程安全的方式操作非线程安全对象内的某一字段,可以不要锁定整个对象,减少锁定的范围,只关注长期、敏感性变化的某一个字段而不是整个对象,以达到精确加锁+节约内存的目的 (类似医生的微创手术)
使用要求
1. 更新的对象属性必须使用public volatile修饰符。
2. 因为对象的属性修改类型原子类都是抽象类,所以每次使用都必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性
代码示例
AtomiclntegerFieldUpdater
以银行存钱为例,银行名称和银行卡号属于基本不会发生变化的字段,而账户余额money属于长期会变化的字段,故只对money加锁,以达到精确加锁+节约内存的目的
更新的对象属性必须使用public volatile修饰符 public volatile int money = 0;
使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性 AtomicIntegerFieldUpdater fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(BankAccount.class,"money");
class BankAccount{
String name = "ccb";
Integer id = 1;
//更新的对象属性必须使用public volatile修饰符。
public volatile int money = 0;
//使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性
AtomicIntegerFieldUpdater fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(BankAccount.class,"money");
public void transfer(BankAccount bankAccount){
fieldUpdater.incrementAndGet(bankAccount);
}
}
public class AtomicIntegerFieldUpdaterDemo {
public static void main(String[] args) throws InterruptedException {
BankAccount bankAccount = new BankAccount();
CountDownLatch latch = new CountDownLatch(1000);
for (int i = 1; i <= 1000; i++) {
new Thread(()->{
try {
bankAccount.transfer(bankAccount);
} catch (Exception e) {
e.printStackTrace();
} finally {
latch.countDown();
}
},String.valueOf(i)).start();
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("账户有多少钱:"+bankAccount.money);
}
}
AtomicReferenceFieldUpdater
多线程并发调用一个类的初始化方法,如果未被初始化过,将执行初始化工作,要求只能初始化一次
class MyVar{
public volatile Boolean isInit = Boolean.FALSE;
AtomicReferenceFieldUpdater<MyVar,Boolean> fieldUpdater = AtomicReferenceFieldUpdater.newUpdater(MyVar.class,
Boolean.class,"isInit");
public void init(MyVar myVar){
if(fieldUpdater.compareAndSet(myVar,Boolean.FALSE,Boolean.TRUE)){
System.out.println(Thread.currentThread().getName()+"\t"+"init start");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"\t"+"end");
}else {
System.out.println(Thread.currentThread().getName()+" 抢修失败,已有线程在执行");
}
}
}
public class AtomicReferenceFieldUpdateDemo {
public static void main(String[] args) {
MyVar myVar = new MyVar();
for (int i = 1; i <= 5; i++) {
new Thread(()->{
myVar.init(myVar);
},String.valueOf(i)).start();
}
}
}