【并发编程】Atomic类

news2024/11/18 5:45:07

一、介绍

在java.util.concurrent.atomic包下atomic一般指原子操作类,主要分为四种类型的原子更新类:原子更新基本类型、原子更新数组类型、原子更新引用和原子更新属性。
在这里插入图片描述

在这里插入图片描述

二、简单使用

1.AtomicInteger

通过synchronized关键字来保证原子性,

    private static int count = 0;
    private static Object object = new Object();
    public static void main(String[] args) throws InterruptedException {
       for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                synchronized (object) {
                    for (int j = 0; j < 10000; j++) {
                        count++;
                    }
                }
            }).start();
        }

        Thread.sleep(1000);
        System.out.println(count); // 100000
   }

通过Atomic类来保证原子性,

    private static AtomicInteger count = new AtomicInteger(0);
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                    for (int j = 0; j < 10000; j++) {
                        count.incrementAndGet();
                    }
            }).start();
        }

        Thread.sleep(1000);
        System.out.println(count); // 100000
    }  

2.AtomicIntegerArray

    static int[] value = new int[]{1,2};
    static AtomicIntegerArray array = new AtomicIntegerArray(value);

    public static void main(String[] args) {
        array.getAndSet(0,3); // 将数组中的下标为0的元素修改为3
        System.out.println(array.get(0)); // 3
        System.out.println(value[0]); // 1,可见AtomicIntegerArray属于深拷贝,不影响原数组的取值
}

3.AtomicReferenceArray

@Data
public class User{
    private String userName;
    public User(String userName){
        this.userName= userName;
    }
}

 static User[] value = new User[]{new User("张三"),new User("李四")};
    static AtomicReferenceArray<User> array = new AtomicReferenceArray(value);
    public static void main(String[] args) {
        System.out.println(array.get(0).getUserName()); // 张三
        array.set(0,new User("王五"));
        System.out.println(array.get(0).getUserName()); // 王五
        System.out.println(value[0].getUserName()); // 张三
    }
@Data
public class User {

    private String userName;

    private Integer age;

    public User() {
    }

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

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

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

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

    static AtomicReferenceFieldUpdater atomic = AtomicReferenceFieldUpdater.newUpdater(User.class,String.class,"userName");
    public static void main(String[] args) {
        User user = new User("张三", 10);
        atomic.set(user,"王五");
        System.out.println(user.getUserName()); // 王五
    }

在这里插入图片描述
需要将userName改为public String userName;
在这里插入图片描述
需要将userName改为public volatile String userName;

三、底层原理

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package java.util.concurrent.atomic;

import java.io.Serializable;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
import sun.misc.Unsafe;

public class AtomicInteger extends Number implements Serializable {
    private static final long serialVersionUID = 6214790243416807050L;
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    // value属性在对象内存当中的偏移量
    private static final long valueOffset;
    private volatile int value;

    public AtomicInteger(int var1) {
        this.value = var1;
    }

    public AtomicInteger() {
    }

    public final int get() {
        return this.value;
    }

    public final void set(int var1) {
        this.value = var1;
    }

    public final void lazySet(int var1) {
        unsafe.putOrderedInt(this, valueOffset, var1);
    }

    public final int getAndSet(int var1) {
        return unsafe.getAndSetInt(this, valueOffset, var1);
    }

    public final boolean compareAndSet(int var1, int var2) {
        return unsafe.compareAndSwapInt(this, valueOffset, var1, var2);
    }

    public final boolean weakCompareAndSet(int var1, int var2) {
        return unsafe.compareAndSwapInt(this, valueOffset, var1, var2);
    }

    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }

    public final int getAndAdd(int var1) {
        return unsafe.getAndAddInt(this, valueOffset, var1);
    }

    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }

    public final int addAndGet(int var1) {
        return unsafe.getAndAddInt(this, valueOffset, var1) + var1;
    }

    public final int getAndUpdate(IntUnaryOperator var1) {
        int var2;
        int var3;
        do {
            var2 = this.get();
            var3 = var1.applyAsInt(var2);
        } while(!this.compareAndSet(var2, var3));

        return var2;
    }

    public final int updateAndGet(IntUnaryOperator var1) {
        int var2;
        int var3;
        do {
            var2 = this.get();
            var3 = var1.applyAsInt(var2);
        } while(!this.compareAndSet(var2, var3));

        return var3;
    }

    public final int getAndAccumulate(int var1, IntBinaryOperator var2) {
        int var3;
        int var4;
        do {
            var3 = this.get();
            var4 = var2.applyAsInt(var3, var1);
        } while(!this.compareAndSet(var3, var4));

        return var3;
    }

    public final int accumulateAndGet(int var1, IntBinaryOperator var2) {
        int var3;
        int var4;
        do {
            var3 = this.get();
            var4 = var2.applyAsInt(var3, var1);
        } while(!this.compareAndSet(var3, var4));

        return var4;
    }

    public String toString() {
        return Integer.toString(this.get());
    }

    public int intValue() {
        return this.get();
    }

    public long longValue() {
        return (long)this.get();
    }

    public float floatValue() {
        return (float)this.get();
    }

    public double doubleValue() {
        return (double)this.get();
    }

    static {
        try {
            // 获得对象的偏移量
            valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception var1) {
            throw new Error(var1);
        }
    }
}

四、Lock、synchronized、Atomic的区别

区别:
(1)ReentrantLock拥有Synchronized相同的并发性和内存语义,两者都是可重入的锁;Lock的实现依赖于cpu级别的指令控制,Synchronized的实现主要由JVM实现控制
(2)synchronized不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定;但是使用Lock则不行,lock是通过代码实现的,要人为保证锁定一定会被释放,就必须将unLock()放到finally{}中,否则可能造成死锁现象
(3)synchronized不是可中断锁,而ReentrantLock是可中断锁。Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
(4)通过ReentrantLock可以知道有没有成功获取锁,而synchronized却无法办到。
(5)synchronized是非公平锁,而ReentrantLock默认实现是非公平锁,但提供公平锁的实现;
(6)ReentrantLock提供读写两种锁操作。

性能比较:
(1)在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,原因在于,编译程序通常会尽可能的进行优化synchronized,另外可读性非常好;但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。
(2)Atomic: 和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为它不能在多个Atomic之间同步。

如何选用:
在JDK1.5中,synchronized的性能是比较低的,线程阻塞和唤醒由操作系统内核完成,频繁的加锁和放锁导致频繁的上下文切换,造成效率低下;因此在多线程环境下,synchronized的吞吐量下降的非常严重。但在JDK1.6时对synchronized进行了很多优化,包括偏向锁、自适应自旋、轻量级锁等措施(synchronized关键字会让没有得到锁资源的线程进入BLOCKED状态,而后在争夺到锁资源后恢复为RUNNABLE状态,这个过程中涉及到操作系统用户模式和内核模式的转换,代价比较高。
尽管JAVA 1.6为synchronized做了优化,增加了从偏向锁到轻量级锁再到重量级锁的过度,但是在转变为重量级锁之后,性能仍然比较低。)。

当需要可定时的、可轮询的与可中断的锁获取操作,公平队列,或者非块结构的锁等高级特性时,才应该使用Lock:否则,请使用synchronized。所以,我们在写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难。针对计数情况,我们就可以使用java中的“原子操作类”。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/82608.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

社交平台数据提取:Social Phone Extractor

Social Phone Extractor是一个功能强大且创新的程序&#xff0c;能够搜索和扫描在 Google / Bing / Yahoo 中索引并与最重要的社交网络&#xff08;如 Linkedin、Facebook、Twitter 和 Instagram&#xff09;相关的个人资料、帖子和文章的页面&#xff0c;然后捕获和推断&#…

ChatGPT介绍世界杯历史与编写足球游戏python程序

ChatGPT聊天机器人最近非常流行&#xff0c;是由OpenAI于本月发布的。花了一点时间注册了一个账号&#xff0c;如有需要帮助注册的可以随时与我交流。注册过程相对有一些复杂。 除了常规的聊天对话功能之外&#xff0c;ChatGPT聊天机器具备强大的文本生成能力&#xff0c;例如博…

【Android】Broadcast广播的使用

一、广播机制概述 通常情况下在学校的每个教室都会装有一个喇叭&#xff0c;这些喇叭是接入到学校广播室的。如果有重要通知&#xff0c;会发送一条广播来告知全校师生。为了便于发送和接收系统级别的消息通知&#xff0c;Android系统也引入了一套类似广播的消息机制。 Android…

股票撤单委托接口是如何操作的?

在交易的过程中&#xff0c;要先通过股票撤单委托接口获取委托单列表的数据&#xff0c;才可以进行撤单的操作&#xff0c;部分的数据会作为参数传递给撤单函数&#xff0c;下面来具体看看股票撤单委托接口是如何操作的&#xff1f; std::cout << " 撤单委托 \n&qu…

025_SSS_BeLFusion: Latent Diffusion for Behavior-Driven Human Motion Prediction

BeLFusion: Latent Diffusion for Behavior-Driven Human Motion Prediction 本文关注的问题是human motion prediction&#xff08;HMP&#xff09;&#xff0c;也就是在给定观测到的人体运动的前提下&#xff0c;预测人体的后续运动。本文的思路是&#xff0c;将人的behavio…

Linux文件服务NFS共享存储服务

作者简介&#xff1a;一名99年软件运维应届毕业生&#xff0c;正在自学云计算课程。宣言&#xff1a;人生就是B&#xff08;birth&#xff09;和D&#xff08;death&#xff09;之间的C&#xff08;choise&#xff09;&#xff0c;做好每一个选择。创作不易&#xff0c;动动小手…

高视医疗在港交所上市:IPO首日跌破发行价,高铁塔为控股股东

12月12日&#xff0c;高视医疗&#xff08;HK:02407&#xff09;在港交所上市。本次上市&#xff0c;高视医疗的发行价确定为每股发售股份51.40港元。据此计算&#xff0c;高视医疗预计募资约6.72亿港元。而招股书则显示&#xff0c;该公司预计募资净额约为2.83亿港元&#xff…

java 剑指 Offer 57 - II. 和为s的连续正数序列

题目所属分类 双指针的做法 O&#xff08;n)的时间复杂度 同时末尾有List<int[]> res 这种的转化成二位数组 原题链接 输入一个正整数 target &#xff0c;输出所有和为 target 的连续正整数序列&#xff08;至少含有两个数&#xff09;。 序列内的数字由小到大排列&…

Spring Boot自定义starters

一、简介 SpringBoot 最强大的功能就是把我们常用的场景抽取成了一个个starter&#xff08;场景 启动器&#xff09;&#xff0c;我们通过引入springboot 为我提供的这些场景启动器&#xff0c;我们再进行 少量的配置就能使用相应的功能。即使是这样&#xff0c;springboot也不…

R语言绘制复杂抽样设计数据cox回归生存曲线(Kaplan-Meier)

上期咱们已经介绍了咱们绘制复杂抽样设计数据的基础图形&#xff0c;今天咱们来介绍一下咱们绘制复杂抽样设计cox回归生存曲线(Kaplan-Meier)。 废话不多说咱们先导入数据和R包 library(survey) pbc<-read.csv("E:/r/test/pbc.csv",sep,,headerTRUE) 这是一个原…

web前端-javascript-prototype原型(说明,访问,优势,判断是否含有一个属性,原型对象的原型)

prototype 原型 1. 原型介绍 function Person() {} function MyClass() {}//向MyClass中添加属性a MyClass.prototype.a 123;//向MyClass的原型中添加一个方法 MyClass.prototype.sayHello function () {alert("hello"); };var mc new MyClass(); var mc2 new …

使用VUE自定义组件封装数据字典实战

背景 照惯例&#xff0c;先交待下背景&#xff0c;从真实需求出发&#xff0c;讲述设计思路和实现方式。 软件系统中&#xff0c;会有一些成组的常量值&#xff0c;来描述业务实体的属性&#xff0c;如性别、证件类型、审批状态等。我们通常称之为数据字典&#xff0c;作为系统…

Seata

Seata的三大角色 TC&#xff08;Transaction Coordinator&#xff09;-事务协调者 维护全局和分支事务的状态&#xff0c;驱动全局事务提交或回滚。 TM&#xff08;Transaction Manager&#xff09;-事务管理器 定义全局事务的范围&#xff1a;开始全局事务、提交或回滚全局…

图片怎么编辑里面的文字?这篇文章告诉你方法

大家平时在分享自己拍摄的照片时&#xff0c;会不会觉得照片有点单调&#xff0c;留白面积大呢&#xff1f;其实这时候&#xff0c;我们可以给图片添加一些文字描述&#xff0c;就能够丰富图片的内容&#xff0c;并且我们也可以将这些加文字的图片当做表情包来使用。那么你们知…

【人工智能】【总结】CMSC5707 Advanced Topics in Artificial Intelligence

文章目录1. 音频信号处理介绍2. 音频信号预处理3. 特征4. 特征重现5. 语音识别6. AdaBoost7. 人脸识别8. 神经网络9. 卷积神经网络10. Auto-Encoder11. 循环神经网络 和 LSTM12. Word Representation13. 决策树1. 音频信号处理介绍 x KHz, y bit, n s 多少 byte: x∗1000∗y/8…

【12月9日更新1/4决赛预测】用二元泊松模型预测2022年世界杯淘汰赛结果

用二元泊松模型预测2022年世界杯淘汰赛结果 网上有很多文章用双泊松&#xff08;Double Poisson&#xff09;模型来预测世界杯比赛结果。但是双泊松模型有一个严重的缺陷&#xff0c;那就是它假设比赛中两队的比分是条件独立的。而我们都知道&#xff0c;在对抗性比赛中&…

【PCB设计】孔间距不可忽视,小心废板!

为什么有时候明明PCB设计没有检查出错误&#xff0c;但是在生产加工后还是出现短路、断板等不良情况&#xff1f; 那是因为你没有考虑到孔间距问题&#xff0c;导致在装配过程中无法避免的产生损耗。 PCB单面板或双面板的制作&#xff0c;都是在下料之后&#xff0c;直接进行非…

商品信息管理系统(Python)完整版

目录 功能模块&#xff1a; 实现思路&#xff1a; 运行功能演示&#xff1a; 具体实现过程&#xff1a; 定义商品类&#xff1a; 定义商品管理类 定义显示商品信息函数 输入销量函数&#xff1a; 添加商品信息&#xff1a; 删除商品信息 修改商品信息 导入商品信息…

Linux下安装Zookeeper教程

ZooKeeper 简介 ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Google的Chubby一个开源的实现&#xff0c;是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件&#xff0c;提供的功能包括&#xff1a;配置维护、域名服…

字符串匹配算法(BFRK)

文章目录题目一、BF算法二、RK算法补充题目 有字符串 str1 和 str2 &#xff0c;str1 中是否包含 str2&#xff0c;如果没有包含返回 -1&#xff0c;如果包含&#xff0c;则返回 str2 在 str1 中开始的位置 注&#xff1a;保证 str1 和 str2 字符串的长度大于 0 举例&#x…