【小家java】原子操作你还在用Synchronized?Atomic、LongAdder你真有必要了解一下了(下)

简介: 【小家java】原子操作你还在用Synchronized?Atomic、LongAdder你真有必要了解一下了(下)

原子更新基本类型


这个使用案例就略了,相信大家再使用他们已经0阻碍了


原子更新数组


当你操作的共享是个数组的话,就可以用这个很方便解决问题了


    public static void main(String[] args) {
        AtomicIntegerArray atomicArray = new AtomicIntegerArray(5);
        // 设置指定索引位的数值
        atomicArray.set(0, 5);
        // 也可以通过以下方法设置 (实际上默认值为0,这里加了5)
        // atomicArray.addAndGet(0, 5);
        // -- 0表示角标
        int current = atomicArray.decrementAndGet(0);
        System.out.println("current = " + current);
    }


   get(int i):获取数组指定位置的值,并不会改变原来的值


   set(int i, int newValue):为数组指定索引位设置一个新值


    getAndSet(int i, int newValue):获取数组指定位置的原始值后,用newValue这个新值进行覆盖。


   getAndAdd(int i, int delta):获取数组指定索引位的原始值后,为数组指定索引位的值增加delta。那么还有个类似的操作为:addAndGet。


   incrementAndGet、decrementAndGet


原子更新引用


使用场景:上面ABA问题有一个非常经典例子,请参加上面


若有类似的使用场景,用对应来存储数据,那么使用这个会非常的方便。例子其实非常简单,这里就不贴出来了,主要介绍一些几个常用的API方法吧:


   get()


   compareAndSet(V expect, V update):如果当前值与给定的expect相等,(注意是引用相等而不是equals()相等),更新为指定的update值。


   .getAndSet(V newValue):原子地设为给定值并返回旧值。


   set(V newValue):不管三七二十一,直接把内存里值设置为此值。


原子更新字段


这个可以算是原子更新引用更新引用的一个很好补充。上面根性我们只能全量更新,并且对象的地址都完全变化了。比如我们要更新一个学生的成绩,如果你new一个带有新成绩的Student进来,那就相当于Student对象都变了,显然是不符合我们要求的。


因此java提供了我们针对字段的跟新的原子操作,可谓是一个很好的补充。

当然啦,它使用起来还是稍微有点麻烦的,它是基于反射实现,该字段还不能是private的,且必须被volatile 修饰。


这个在业务上几乎涉及不到,但是在我们框架设计行,还是有可能被适用到的。比如我们内部定义一颗树,可以设计为:


private volatile Node left, right;


因为使用极少,因此有兴趣的朋友可以自己去玩玩,这里就略过吧


JDK8新增


DoubleAccumulator、LongAccumulator、DoubleAdder、LongAdder


今天看到阿里巴巴的手册里面说 ,如果你使用的JDK8和以上版本,建议使用LongAdder代替AotmicLong


受限于文章篇幅,关于他们的使用以及和LongAdder和AotmicLong的性能测试对比,请移步这篇博文专门讲解:【小家java】AtomicLong可以抛弃了,请使用LongAdder代替(或使用LongAccumulator)


悲观锁和乐观锁(Java都提供了对应支持)


为了更好的理解上面的一些操作原理,本文有必要稍带讲解一些悲观锁和乐观锁的概念以及区别


在本文讲解悲观锁和乐观锁,主要代表是synchronized和CAS的区别


悲观锁


悲观锁是一种独占锁,它假设的前提是“冲突一定会发生”,所以处理某段可能出现数据冲突的代码时,这个代码段就要被某个线程独占。而独占意味着“其它即将执行这段代码的其他线程”都将进入“阻塞”/“挂起”状态。


synchronized关键字就是java对于悲观锁的实现。


由于悲观锁的影响下,其他线程都将进入 阻塞/挂起 状态。而我们知道,CPU执行线程状态切换是要耗费相当资源的,这主要涉及到CPU寄存器的操作。所以悲观锁在性能上不会有太多惊艳的表现(但是一般也不至于成为性能瓶颈,所以各位也不要一棒子打死)


乐观锁


乐观锁假定“冲突不一定会出现”,如果出现冲突则进行重试,直到冲突消失。 由于乐观锁的假定条件,所以乐观锁不会独占资源,性能自然在**多数情况下**就会好于悲观锁。


AtomicInteger是一个标准的乐观锁实现,sun.misc.Unsafe是JDK提供的乐观锁的支持。

    public final long getAndAddLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);
        } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
        return var6;
    }

为什么是多数情况呢?因为一旦多线程对某个资源的抢占频度达到了某种规模,就会导致乐观锁内部出现多次更新失败的情况,最终造成乐观锁内部进入一种“活锁”状态。这时乐观锁的性能反而没有悲观锁好。


如果我们很好的理解了乐观锁,并且能很熟练的应用的话,我们可以把它运用到我们项目了,帮助改善性能,比一遇到并发问题就去使用悲观锁的选手,显得更加的NB轰轰了有木有

相关文章
|
6月前
|
安全 算法 Java
Java 中 synchronized 与 AtomicInteger 的区别
在Java多线程编程中,`synchronized`和`AtomicInteger`均用于实现线程安全,但原理与适用场景不同。`synchronized`是基于对象锁的同步机制,适用于复杂逻辑和多变量同步,如银行转账;而`AtomicInteger`采用CAS算法,适合单一变量的原子操作,例如计数器更新。二者各有优劣,应根据具体需求选择使用。
202 0
|
8月前
|
安全 Java 程序员
【高薪程序员必看】万字长文拆解Java并发编程!(6-2):从CAS无锁机制到Atomic原子类实战指南
🌟 ​🌟今天给大家带来的是 ​💻⚡在这篇文章中,我们将一起探索:🔹 ​的底层原理,它是如何通过 ​实现无锁并发的?🔹 ​的终极对决,为什么高并发场景下CAS性能更优?🔹 ​的陷阱与解决方案——和实战演示!🔹 ​​(LongAdder等)的使用场景与性能对比🔹 危险的 ​黑魔法:为什么阿里禁止使用却又是并发库的基石?无论你是:✅ ​​(BATJ高频考点)✅ ​​(如何设计百万级计数器)✅ ​​(从Java代码到CPU指令的全链路分析)这篇文章都会让你收获满满!✨。
124 0
|
8月前
|
安全 Java 程序员
【高薪程序员必看】万字长文拆解Java并发编程!(6-1):从CAS无锁机制到Atomic原子类实战指南
🌟 ​🌟今天给大家带来的是 ​💻⚡在这篇文章中,我们将一起探索:🔹 ​的底层原理,它是如何通过 ​实现无锁并发的?🔹 ​的终极对决,为什么高并发场景下CAS性能更优?🔹 ​的陷阱与解决方案——和实战演示!🔹 ​​(LongAdder等)的使用场景与性能对比🔹 危险的 ​黑魔法:为什么阿里禁止使用却又是并发库的基石?无论你是:✅ ​​(BATJ高频考点)✅ ​​(如何设计百万级计数器)✅ ​​(从Java代码到CPU指令的全链路分析)这篇文章都会让你收获满满!✨。
126 0
|
8月前
|
人工智能 安全 Java
Java并发包下Atomic相关类的使用
本文介绍了 `java.util.concurrent.atomic` 包下的各类原子类及其使用场景,包括基本类型原子类(如 `AtomicInteger`、`AtomicLong`)、数组类型原子类(如 `AtomicIntegerArray`)、引用类型原子类(如 `AtomicReference`)、对象属性修改原子类(如 `AtomicIntegerFieldUpdater`)以及原子操作增强类(如 `LongAdder` 和 `LongAccumulator`)。同时,详细对比了不同原子类在高并发场景下的性能表现,展示了 `LongAdder` 的高效性。
216 31
|
10月前
|
存储 缓存 人工智能
【原理】【Java并发】【synchronized】适合中学者体质的synchronized原理
本文深入解析了Java中`synchronized`关键字的底层原理,从代码块与方法修饰的区别到锁升级机制,内容详尽。通过`monitorenter`和`monitorexit`指令,阐述了`synchronized`实现原子性、有序性和可见性的原理。同时,详细分析了锁升级流程:无锁 → 偏向锁 → 轻量级锁 → 重量级锁,结合对象头`MarkWord`的变化,揭示JVM优化锁性能的策略。此外,还探讨了Monitor的内部结构及线程竞争锁的过程,并介绍了锁消除与锁粗化等优化手段。最后,结合实际案例,帮助读者全面理解`synchronized`在并发编程中的作用与细节。
783 8
【原理】【Java并发】【synchronized】适合中学者体质的synchronized原理
|
10月前
|
缓存 安全 Java
【Java并发】【synchronized】适合初学者体质入门的synchronized
欢迎来到我的Java线程同步入门指南!我不是外包员工,梦想是写高端CRUD。2025年我正在沉淀中,博客更新速度加快,欢迎点赞、收藏、关注。 本文介绍Java中的`synchronized`关键字,适合初学者。`synchronized`用于确保多个线程访问共享资源时不会发生冲突,避免竞态条件、保证内存可见性、防止原子性破坏及协调多线程有序访问。
306 8
【Java并发】【synchronized】适合初学者体质入门的synchronized
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
319 7
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
556 3
|
Java 开发者
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
188 4
|
安全 Java 开发者
java的synchronized有几种加锁方式
Java的 `synchronized`通过上述三种加锁方式,为开发者提供了从粗粒度到细粒度的并发控制能力,满足了不同场景下的线程安全需求。合理选择加锁方式对于提升程序的并发性能和正确性至关重要,开发者应根据实际应用场景的特性和性能要求来决定使用哪种加锁策略。
225 0