AtomicReference

AtomicReference类提供了一个可以原子读写的对象引用变量。 原子意味着尝试更改相同AtomicReference的多个线程(例如,使用比较和交换操作)不会使AtomicReference最终达到不一致的状态。 AtomicReference甚至有一个先进的compareAndSet()方法,它可以将引用与预期值(引用)进行比较,如果它们相等,则在AtomicReference对象内设置一个新的引用。

AtomicStampReference 安全的修改一个变量的值

package com.keytech.task;import org.junit.platform.commons.logging.LoggerFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;/*** @className: AtomicIntegerTest* @description: TODO 类描述* @author: mac* @date: 2020/12/29**///线程安全public class AtomicIntegerTest {private static AtomicReference<Integer> count=new AtomicReference<>(0);public static void main(String[] args) {//如果期望值是0,则修改成2count.compareAndSet(0, 2); //ok//如果期望值是1,则修改成4count.compareAndSet(1, 4); //no ok//如果期望值是2,则修改成8count.compareAndSet(2, 8); //okSystem.out.println(count.get());}
}//输出8

如果AtomicReference<T>T是一个自定义的对象,线程安全?

public class AtomicReference<V> implements java.io.Serializable {private static final long serialVersionUID = -1848883965231344442L;private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicReference.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile V value;/*** Creates a new AtomicReference with the given initial value.** @param initialValue the initial value*/public AtomicReference(V initialValue) {value = initialValue;}/*** Creates a new AtomicReference with null initial value.*/public AtomicReference() {}/*** 不需要安全防护*/public final V get() {return value;}/*** 设值值不需要进行对象安全防护*/public final void set(V newValue) {value = newValue;}/*** 很明显调用的是csa操作* 比较对象是否相同,进行设值* 设值成功返回true,否则返回false*/public final boolean compareAndSet(V expect, V update) {return unsafe.compareAndSwapObject(this, valueOffset, expect, update);}/*** 设置新的值并且返回旧的值* 原子操作*/@SuppressWarnings("unchecked")public final V getAndSet(V newValue) {return (V)unsafe.getAndSetObject(this, valueOffset, newValue);}
}

compareAndSet采用CAS保证并发

AtomicReference 所提供的某些方法可以进行原子性操作,如compareAndSet、getAndSet,这仅仅是对引用进行原子性操作

AtomicReference 不能保证对象中若存在属性值修改是线程安全的,如假设引用对象是person,修改person中name和age,多个线程同时从引用中获得对象,并进行修改,会出现线程不安全情况。下面我们通过代码来验证一下这条结论。

AtomicReference不安全的修改自定义对象属性的值

package com.keytech.task;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicReference;/*** @className: AtomicReferenceTest* @description: TODO 类描述* @author: mac* @date: 2020/12/29**/
public class AtomicReferenceTest {private static Integer clientTotal=5000;private static Integer threadTotal=200;private static Rumenz rumenz=new Rumenz(0,0);private static AtomicReference<Rumenz> rumenzReference=new AtomicReference<>(rumenz);public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();Semaphore semaphore=new Semaphore(threadTotal);for (int i = 0; i < clientTotal; i++) {final  Integer n=i;executorService.execute(()->{try{semaphore.acquire();update(n);semaphore.release();}catch (Exception e){e.printStackTrace();}});}executorService.shutdown();System.out.println("rumenzReference="+rumenzReference.get().getAge());System.out.println("rumenzReference="+rumenzReference.get().getName());}//如果线程安全的话,age的值和name的值是一致的//如果线程不安全的话,age的值和name是不一样的。private static void update(int i){rumenzReference.get().setAge(rumenzReference.get().getAge()+i);rumenzReference.get().setName(rumenzReference.get().getName()+i);}
}class Rumenz{private Integer age;private Integer name;public Rumenz(Integer age, Integer name) {this.age = age;this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Integer getName() {return name;}public void setName(Integer name) {this.name = name;}
}

在低并发情况下可以得到正确的结果,但是高并发情况下就会出现差异.因为自定义的对象在访问时用的是set,get没有CAS,所以导致线程不安全.

通过AtomicintegerFieldUpdater安全的修改自定义对象

atomic包中提供AtomicReferenceFieldUpdaterAtomicIntegerFieldUpdaterAtomicLongFieldUpdater,原子性的更新某一个类实例的指定的某一个字段.

AtomicIntegerFieldUpdater

通过CAS修改变量值

package com.keytech.task;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;/*** @className: AtomicIntegerFieldUpdaterTest* @description: TODO 类描述* @author: mac* @date: 2020/12/29**/
public class AtomicIntegerFieldUpdaterTest {private static AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> upCount=AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdaterTest.class,"count");public int getCount() {return count;}public volatile int count=100;public static void main(String[] args) {AtomicIntegerFieldUpdaterTest obj=new AtomicIntegerFieldUpdaterTest();if(upCount.compareAndSet(obj,100,200)){System.out.println("修改成功"+obj.getCount());}if(upCount.compareAndSet(obj,100,200)){System.out.println("修改成功");}else{System.out.println("修改失败");}}
}//修改成功200
//修改失败

AtomicIntegerFieldUpdater源码分析

public abstract class AtomicIntegerFieldUpdater<T> {/**** @param tclass 持有某字段的类* @param fieldName 字段名字*/@CallerSensitivepublic static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,String fieldName)     {return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());}/*** 原子性设置*/public int getAndSet(T obj, int newValue) {int prev;do {prev = get(obj);} while (!compareAndSet(obj, prev, newValue));return prev;}private static class AtomicIntegerFieldUpdaterImpl<T>extends AtomicIntegerFieldUpdater<T> {private static final Unsafe unsafe = Unsafe.getUnsafe();private final long offset;private final Class<T> tclass;private final Class<?> cclass;AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,final String fieldName,final Class<?> caller) {final Field field;final int modifiers;try {field = AccessController.doPrivileged(new PrivilegedExceptionAction<Field>() {public Field run() throws NoSuchFieldException {//字段不存在会抛异常return tclass.getDeclaredField(fieldName);}});//检查访问级别modifiers = field.getModifiers();sun.reflect.misc.ReflectUtil.ensureMemberAccess(caller, tclass, null, modifiers);ClassLoader cl = tclass.getClassLoader();ClassLoader ccl = caller.getClassLoader();if ((ccl != null) && (ccl != cl) &&((cl == null) || !isAncestor(cl, ccl))) {sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);}} catch (PrivilegedActionException pae) {throw new RuntimeException(pae.getException());} catch (Exception ex) {throw new RuntimeException(ex);}Class<?> fieldt = field.getType();//必须是intif (fieldt != int.class)throw new IllegalArgumentException("Must be integer type");//必须用volatile修饰if (!Modifier.isVolatile(modifiers))throw new IllegalArgumentException("Must be volatile type");this.cclass = (Modifier.isProtected(modifiers) &&caller != tclass) ? caller : null;this.tclass = tclass;//用Unsafe里的那一坨方法去原子更新offset = unsafe.objectFieldOffset(field);}}
}

AtomicIntegerFieldUpdater线程安全的更新自定义对象的属性值

package com.keytech.task;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
/*** @className: AtomicReferenceTest* @description: TODO 类描述* @author: mac* @date: 2020/12/29**/
public class AtomicReferenceTest {private static Integer clientTotal=5000;private static Integer threadTotal=200;public static Rumenz rumenz=new Rumenz(0,0);public static AtomicIntegerFieldUpdater<Rumenz> rumenzReferenceAge= AtomicIntegerFieldUpdater.newUpdater(Rumenz.class,"age");private static AtomicIntegerFieldUpdater<Rumenz> rumenzReferenceName= AtomicIntegerFieldUpdater.newUpdater(Rumenz.class,"name");public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();Semaphore semaphore=new Semaphore(threadTotal);for (int i = 0; i < clientTotal; i++) {final  Integer n=i;executorService.execute(()->{try{semaphore.acquire();update(n);semaphore.release();}catch (Exception e){e.printStackTrace();}});}executorService.shutdown();System.out.println("rumenzReference="+ rumenz.getAge());System.out.println("rumenzReference="+ rumenz.getName());}public static void update(int i){rumenzReferenceAge.incrementAndGet(rumenz);rumenzReferenceName.incrementAndGet(rumenz);}
}class Rumenz{//必须加volatile 如果是整数不能写包装类型:如不能为Integerpublic volatile  int age;public volatile  int name;public Rumenz(Integer age, Integer name) {this.age = age;this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Integer getName() {return name;}public void setName(Integer name) {this.name = name;}
}//rumenzReference=5000
//rumenzReference=5000

AtomicReference原子性引用相关推荐

  1. java 原子引用_Java 原子性引用 AtomicReference

    更多 Java 并发编程方面的文章,请参见文集<Java 并发编程> AtomicReference An object reference that may be updated ato ...

  2. java原子引用怎么理解_Java 原子性引用 AtomicReference

    AtomicReference An object reference that may be updated atomically. The AtomicReference class provid ...

  3. AtomicReference 原子引用

    原创 2016年03月04日 13:35:20 7638 1.简介 赋值操作不是线程安全的.若想不用锁来实现,可以用AtomicReference<V>这个类,实现对象引用的原子更新. 使 ...

  4. Java并发编程-原子性变量

    image.png 1. 原子性布尔 AtomicBoolean AtomicBoolean 类为我们提供了一个可以用原子方式进行读和写的布尔值,它还拥有一些先进的原子性操作,比如 compareAn ...

  5. 高并发编程之AtomicReference使用场景

    Java并发--AtomicReferencen,解决并发时修改多个属性 记录一下工作中,mycat主从延迟,缓存数据有误解决方案 一.AtomicReference介绍 1-AtomicRefere ...

  6. java 取整型的低八位_Java 基础(十五)并发工具包 concurrent

    本文目录: java.util.concurrent - Java 并发包简介 阻塞队列 BlockingQueue 数组阻塞队列 ArrayBlockingQueue 延迟队列 DelayQueue ...

  7. Java并发编程-并发工具包(java.util.concurrent)使用指南(全)

    1. java.util.concurrent - Java 并发工具包 Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包.这个包包含有一系列能够让 Ja ...

  8. Java并发编程-并发工具包java.util.concurrent使用指南

    译序 本指南根据 Jakob Jenkov 最新博客翻译,请随时关注博客更新 本指南已做成中英文对照阅读版的 pdf 文档,有兴趣的朋友可以去 Java并发工具包java.util.concurren ...

  9. Java高并发编程:原子类

    1. 并发编程概念 原子性 一个操作不能被再拆分了:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行.一个很经典的例子就是银行账户转账问题. 增量操作符++,不是原 ...

最新文章

  1. 计算机程序的思维逻辑 (43) - 剖析TreeMap
  2. linux命令scp
  3. 剑指offer-合并链表
  4. (92)低速接口UART、IIC、SPI介绍,面试必问(十六)(第19天)
  5. Flink当中使用kafka Consumer
  6. Yam旗下Degenerative Finance明日将上线uSTONKS和uGAS奖励计划
  7. aidl远程服务调用Android,报错:Process 'command 'F:\Android\SDK\build-tools\29.0.0\aidl.exe''
  8. 整装待发 QTA UI自动化测试框架迎来大更新
  9. 计算机网络应用基础_学习笔记之《计算机网络》概述
  10. tomcat web服务器优化
  11. 面试题: ,| 与,||的区别?
  12. clustalw序列比对_CLUSTALW(muscle序列比对)
  13. 层次分析法(AHP)——MATLAB在数学建模中的应用(第2版)
  14. 上海法院驳回深圳唯冠停止销售苹果iPad禁令
  15. ZoneAlarm 不错的防火墙软件
  16. 若依前后端分离项目图片上传后访问404问题
  17. python情绪识别_使用百度对话情绪识别api分析文本
  18. 0x01 前情提要随着疫情反复,今天我在家办公。我需要登一台服务器上配置,但是那个地址只能通过深信服vpn连接,在家办公一天就带了台kali系统的笔记本回来,没带windows的。 kali上
  19. 13个可以为网站创建360度全景视图的工具
  20. LDA与PCA数据降维算法理论与实现(基于python)

热门文章

  1. Python处理各种压缩文件(bzip2,gzip,zip)
  2. java实现多线程抢单_来聊一聊3种实现JAVA多线程的方式吧
  3. PAT 乙级 1009. 说反话 (20) Java版
  4. 蓝桥杯 ALGO-90 算法训练 出现次数最多的整数
  5. 【Objective-C】栈(stack)和堆(heap)的区别
  6. 如何打印网页版的发票_纸质发票将消失,电子发票如何报销、打印、收集?这一篇就够了...
  7. php的4种常用运行方式
  8. java 获取mongodb的连接数
  9. Spring + Ibatis + MySql实例详解
  10. 创建对象、原型、原型链