【多线程】原子类

JDK原子类基于CAS轻量级原子操作实现,使得程序运行效率变得更高。

 

(1)基本原子类
基本原子类的功能是通过原子方式更新Java基础类型变量的值。基本原子类主要包括以下三个:
 AtomicInteger:整型原子类。
 AtomicLong:长整型原子类。
 AtomicBoolean:布尔型原子类。


(2)数组原子类
数组原子类的功能是通过原子方式更新数组中的某个元素的值。数组原子类主要包括了以下
三个:
 AtomicIntegerArray:整型数组原子类。
 AtomicLongArray:长整型数组原子类。
 AtomicReferenceArray:引用类型数组原子类。


(3)引用原子类   保证对象引用的原子性
引用原子类主要包括以下三个:
 AtomicReference:引用类型原子类。
 AtomicMarkableReference:带有更新标记位的原子引用类型。
 AtomicStampedReference:带有更新版本号的原子引用类型。
AtomicMarkableReference类将boolean标记与引用关联起来,可以解决使用AtomicBoolean进行原子方式的更新时可能出现的ABA问题。
AtomicStampedReference类将整数值与引用关联起来,可以解决使用AtomicInteger进行原子方式的更新时可能出现的ABA问题。

引用原子类测试

复制代码
public class User implements Serializable
{
    String uid; //用户ID
    String nickName; //昵称
    public volatile int age; //年龄
    public User(String uid, String nickName)
    {
        this.uid = uid;
        this.nickName = nickName;
    }    
复制代码

测试代码:

复制代码
public class AtomicTest
{
    @Test
    public void testAtomicReference()
    {
        //包装的原子对象
        AtomicReference<User> userRef = new AtomicReference<User>();
        //待包装的User对象
        User user = new User("1", "张三");
        //为原子对象设置值
        userRef.set(user);
        Print.tco("userRef is:" + userRef.get());
        //要使用CAS替换的User对象
        User updateUser = new User("2", "李四");
        //使用CAS替换
        boolean success = userRef.compareAndSet(user, updateUser);
        Print.tco(" cas result is:" + success);
        Print.tco(" after cas,userRef is:" + userRef.get());
    } 
}
复制代码

首先创建了一个User对象,然后把User对象包装到一个AtomicReference类型的引用userRef中,如果要修改userRef的包装值,就需要调用compareAndSet()方法才能完成。该方法就是通过CAS操作userRef,从而保证操作的原子性。

使用原子引用类型AtomicReference包装了User对象之后,只能保障User引用的原子操作,对被包装的User对象的字段值修改时不能保证原子性,这点要切记。

 

(4)字段更新原子类:如果需要保障对象某个字段(或者属性)更新操作的原子性,需要用到属性更新原子类
字段更新原子类主要包括以下三个:
 AtomicIntegerFieldUpdater:原子更新整型字段的更新器。
 AtomicLongFieldUpdater:原子更新长整型字段的更新器。
 AtomicReferenceFieldUpdater:原子更新引用类型里的字段。

要求:

 第一步,更新的对象属性必须使用public volatile修饰符。
 第二步,因为对象的属性修改类型原子类都是抽象类,所以每次使用都必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。

同时可以减少内存,参考 https://juejin.cn/post/7139065982034640909

 

字段更新原子类测试:继续基于上面的User类测试

复制代码
public void testAtomicIntegerFieldUpdater()
{
    //使用静态方法newUpdater()创建一个更新器updater
    AtomicIntegerFieldUpdater<User> updater= AtomicIntegerFieldUpdater.newUpdater(User.class, "age");
    User user = new User("1", "张三");
    //使用属性更新器的getAndIncrement、getAndAdd增加user的age值
    Print.tco(updater.getAndIncrement(user)); // 1
    Print.tco(updater.getAndAdd(user, 100)); // 101
    //使用属性更新器的get获取user的age值
    Print.tco(updater.get(user)); // 101
}
复制代码

运行以上代码,结果如下:
[main]:0
[main]:1
[main]:101

实际应用AtomicIntegerFieldUpdater是static final只占用一份内存,不会因为实例的创建而增加。在对象有几十万,几百万的场景下(如百万级设备连接)可节约大量的内存。

 

posted @   飞翔在天  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示