首页 > 其他分享 >原子操作类Atomic

原子操作类Atomic

时间:2024-07-26 21:53:02浏览次数:14  
标签:int age 更新 原子 Atomic 操作 public User

原子操作的基本数据类型


基本类型的原子操作主要有这些:

  1. AtomicBoolean:以原子更新的方式更新 boolean;
  2. AtomicInteger:以原子更新的方式更新 Integer;
  3. AtomicLong:以原子更新的方式更新 Long;

这几个类的用法基本一致,这里以 AtomicInteger 为例。

  1. addAndGet(int delta) :增加给定的 delta,并获取新值。
  2. incrementAndGet():增加 1,并获取新值。
  3. getAndSet(int newValue):获取当前值,并将新值设置为 newValue。
  4. getAndIncrement():获取当前值,并增加 1。

AtomicInteger 的 getAndIncrement 方法:

public final int getAndIncrement() {
    // 使用Unsafe类中的getAndAddInt方法原子地增加AtomicInteger的当前值
    // 第一个参数this是AtomicInteger的当前实例
    // 第二个参数valueOffset是一个偏移量,它指示在AtomicInteger对象中的哪个位置可以找到实际的int值
    // 第三个参数1表示要加到当前值上的值(即增加的值)
    // 此方法返回的是增加前的原始值
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

Unsafe 类是 Java 中的一个特殊类,用于执行低级、不安全的操作。getAndIncrement 方法就是利用了 Unsafe 类提供的 CAS(Compare-And-Swap)操作来实现原子的 increment 操作。CAS 是一种常用的无锁技术,允许在多线程环境中原子地更新值。

示例:

public class Main {
    private static final AtomicInteger atomicInteger = new AtomicInteger(1);

    public static void main(String[] args) {
        System.out.println(atomicInteger.getAndIncrement());
        System.out.println(atomicInteger.get());
    }
}

AtomicBoolean 类的 compareAndSet 方法:

public final boolean compareAndSet(boolean expect, boolean update) {
    // 将expect布尔值转化为整数,true为1,false为0
    int e = expect ? 1 : 0;
    
    // 将update布尔值转化为整数,true为1,false为0
    int u = update ? 1 : 0;
    
    // 使用Unsafe类中的compareAndSwapInt方法尝试原子地更新AtomicBoolean的当前值
    // 第一个参数this是AtomicBoolean的当前实例
    // 第二个参数valueOffset是一个偏移量,它指示在AtomicBoolean对象中的哪个位置可以找到实际的int值
    // 第三个参数e是我们期望的当前值(转换为整数后的值)
    // 第四个参数u是我们想要更新的值(转换为整数后的值)
    // 如果当前值与期望值e相等,它会被原子地设置为u,并返回true;否则返回false。
    return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}

原子操作的数组类型


如果需要原子更新数组里的某个元素,atomic 也提供了相应的类:

  1. AtomicIntegerArray:这个类提供了一些原子更新 int 整数数组的方法。
  2. AtomicLongArray:这个类提供了一些原子更新 long 型证书数组的方法。
  3. AtomicReferenceArray:这个类提供了一些原子更新引用类型数组的方法。

这几个类的用法一致,就以 AtomicIntegerArray 来总结下常用的方法:

  1. addAndGet(int i, int delta):以原子更新的方式将数组中索引为 i 的元素与输入值相加;
  2. getAndIncrement(int i):以原子更新的方式将数组中索引为 i 的元素自增加 1;
  3. compareAndSet(int i, int expect, int update):将数组中索引为 i 的位置的元素进行更新

示例:

public class Main {
    private static final int[] value = new int[]{1, 2, 3};
    private static final AtomicIntegerArray integerArray = new AtomicIntegerArray(value);

    public static void main(String[] args) {
        // 对数组中索引为1的位置的元素加5
        int result = integerArray.getAndAdd(1, 5);
        System.out.println(integerArray.get(1));
        System.out.println(result);
    }
}

原子操作的引用类型


如果需要原子更新引用类型的话,atomic 也提供了相关的类:

  1. AtomicReference:原子更新引用类型;
  2. AtomicReferenceFieldUpdater:原子更新引用类型里的字段;
  3. AtomicMarkableReference:原子更新带有标记位的引用类型;

示例:

public class Main {
    private static final AtomicReference<User> reference = new AtomicReference<>();

    public static void main(String[] args) {
        User user1 = new User("a", 1);
        reference.set(user1);
        User user2 = new User("b", 2);
        User user = reference.getAndSet(user2);
        System.out.println(user);
        System.out.println(reference.get());
    }

    static class User {
        private final String userName;
        private final int age;

        public User(String userName, int age) {
            this.userName = userName;
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +
                    "userName='" + userName + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}

原子更新字段类型


如果需要更新对象的某个字段,atomic 同样也提供了相应的原子操作类:

  1. AtomicIntegeFieldUpdater:原子更新整型字段类;
  2. AtomicLongFieldUpdater:原子更新长整型字段类;
  3. AtomicStampedReference:原子更新引用类型,这种更新方式会带有版本号,是为了解决 CAS 的 ABA 问题

使用原子更新字段需要两步:

  1. 通过静态方法newUpdater创建一个更新器,并且设置想要更新的类和字段;
  2. 字段必须使用public volatile进行修饰;

示例:

public class Main {
    private static final AtomicIntegerFieldUpdater<User> updater = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");

    public static void main(String[] args) {
        User user = new User("a", 1);
        int oldValue = updater.getAndAdd(user, 5);
        System.out.println(oldValue);
        System.out.println(updater.get(user));
    }

    static class User {
        private final String userName;
        public volatile int age;

        public User(String userName, int age) {
            this.userName = userName;
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +
                    "userName='" + userName + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}

标签:int,age,更新,原子,Atomic,操作,public,User
From: https://www.cnblogs.com/sprinining/p/18326333

相关文章

  • Linux内核链表源码的简单操作
    一、Linux内核链表源码的获取下载系统源码的方法常见的有两种:第一种访问网站下载:kernel.org第二种输入Linux命令下载:sudoaptinstalllinux-source-5.15.0(一般这种下载的是当前系统所用到的系统源码版本)下载完之后在/usr/src中可找到系统源码的压缩包,可以解压......
  • 探索Perl的文件系统抽象层:驾驭文件操作的无形之手
    探索Perl的文件系统抽象层:驾驭文件操作的无形之手在Perl编程中,文件系统抽象层(FileSystemAbstractionLayer,简称FSAL)是一种允许开发者以统一的方式处理不同文件系统特性的机制。FSAL隐藏了底层文件系统的具体实现细节,提供了一套标准化的接口来访问和管理文件系统中的资源......
  • 抢先体验快人一步iOS18操作系统升级方法
    前段时间iOS18的首个公测版发布上线了,对于想要尝鲜测试的朋友们,可以开始升级到iOS18系统啦。如果不知道怎么升级的话,可以随小编一起来看看。一、目前支持iOS18的机型有iPhone:iPhoneXR、iPhoneXs/XsMax;iPhone11/11Pro/11ProMaxiPhone12/12Pro/12ProMax/12min......
  • hive03_高级操作
    Hive分区表https://blog.csdn.net/weixin_41122339/article/details/81584110表在存储时,可以将数据根据分区键的列值存储在表目录的子目录中。这样将数据切分到不同目录存储后,可以加快对分区键字段的查询和过滤速度,通过在查询条件中指定过滤条件,可以只对指定目录的数据进行扫......
  • hive02_SQL操作
    HiveDDL操作操作前需要保证hive成功启动:#启动HiveServer2hive--servicehiveserver2&#启动MetaStorehive--servicemetastore&#进入hive命令行界面beeline-ujdbc:hive2://node03:10000-nroot数据库操作操作类似于MySQL数据库操作。表基本操作h......
  • 顺序表的实现和操作
    目录一.前言二.顺序表的优缺点三.顺序表的定义和初始化四.顺序表的相关操作一.前言    首先介绍下线性表的定义,线性表是具有相同特性的数据元素的一个有限序列。而我们的顺序表就是线性表的一种,是线性表的顺序存储结构。所谓顺序存储就是把逻辑上相邻的数据......
  • 单链表的实现和操作
    目录一.前言二.单链表的定义和结构三.单链表的操作一.前言    线性表的链式表示又称为非顺序映像或链式映像。简而言之,链表可以理解为由指针链连接的n个结点组成的。其中每一个结点包括数据域和指针域。值得注意的是,与顺序表不同,链表中的逻辑次序与物理次序不......
  • es6中对数组的常用操作方法-普通数组
    参考https://www.jianshu.com/p/856f4200d3c0最近,经常操作数组,可是数组中的一些常用操作方法很迷糊,看了上面一篇文章之后,茅塞顿开。于是自己按照上面文章的用法,自己全部从头到尾写了一遍,分为普通的数组以及对象数组的操作。//定义数组constarr=[1,2,3,4,5]......
  • es6中对数组的常用操作方法-对象数组
    //定义对象数组constarrayObject=[{name:'name1',title:'title1'},{name:'name2',title:'title2'},{name:'name3',title:'title3'}];//数组对象......
  • Python Selenium 操作链可以工作,但会停止我在 Firefox 中的程序
    我有时使用ActionsChains时遇到任何问题,今天它不起作用,你知道为什么吗?scrolling_bar=driver.find_element(By.CSS_SELECTOR,"#scrolling_bar")start=scrolling_bar.locationActionChains(driver)\.drag_and_drop_by_offset(scrolling_bar,start......