【小家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轰轰了有木有

相关文章
|
1天前
|
存储 安全 Java
Java中synchronized锁的深入理解
Java中synchronized锁的深入理解
21 1
|
1天前
|
安全 算法 Java
Java一分钟:线程同步:synchronized关键字
【5月更文挑战第11天】Java中的`synchronized`关键字用于线程同步,防止竞态条件,确保数据一致性。本文介绍了其工作原理、常见问题及避免策略。同步方法和同步代码块是两种使用形式,需注意避免死锁、过度使用导致的性能影响以及理解锁的可重入性和升级降级机制。示例展示了同步方法和代码块的运用,以及如何避免死锁。正确使用`synchronized`是编写多线程安全代码的核心。
57 2
|
1天前
|
安全 Java 程序员
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
12 0
|
1天前
|
存储 安全 Java
【亮剑】Java并发编程涉及`ThreadLocal`、`Volatile`、`Synchronized`和`Atomic`四个关键机制
【4月更文挑战第30天】Java并发编程涉及`ThreadLocal`、`Volatile`、`Synchronized`和`Atomic`四个关键机制。`ThreadLocal`为每个线程提供独立变量副本;`Volatile`确保变量可见性,但不保证原子性;`Synchronized`实现同步锁,保证单线程执行;`Atomic`类利用CAS实现无锁并发控制。理解其原理有助于编写高效线程安全代码。根据业务场景选择合适机制至关重要。
|
1天前
|
安全 Java 编译器
【Java EE】总结12种锁策略以及synchronized的实现原理
【Java EE】总结12种锁策略以及synchronized的实现原理
|
1天前
|
安全 Java 编译器
是时候来唠一唠synchronized关键字了,Java多线程的必问考点!
本文简要介绍了Java中的`synchronized`关键字,它是用于保证多线程环境下的同步,解决原子性、可见性和顺序性问题。从JDK1.6开始,synchronized进行了优化,性能得到提升,现在仍可在项目中使用。synchronized有三种用法:修饰实例方法、静态方法和代码块。文章还讨论了synchronized修饰代码块的锁对象、静态与非静态方法调用的互斥性,以及构造方法不能被同步修饰。此外,通过反汇编展示了`synchronized`在方法和代码块上的底层实现,涉及ObjectMonitor和monitorenter/monitorexit指令。
26 0
|
1天前
|
安全 Java 调度
Java中,synchronized关键字你了解多少?
【4月更文挑战第16天】
55 14
|
1天前
|
安全 Java 开发者
Java并发编程:深入理解Synchronized关键字
【4月更文挑战第19天】 在Java多线程编程中,为了确保数据的一致性和线程安全,我们经常需要使用到同步机制。其中,`synchronized`关键字是最为常见的一种方式,它能够保证在同一时刻只有一个线程可以访问某个对象的特定代码段。本文将深入探讨`synchronized`关键字的原理、用法以及性能影响,并通过具体示例来展示如何在Java程序中有效地应用这一技术。
|
1天前
|
Java
浅谈Java的synchronized 锁以及synchronized 的锁升级
浅谈Java的synchronized 锁以及synchronized 的锁升级
8 0
|
1天前
|
Java
Java中的线程同步:synchronized关键字的深度解析
【4月更文挑战第14天】在多线程环境下,线程同步是一个重要的话题。Java提供了多种机制来实现线程同步,其中最常用且最重要的就是synchronized关键字。本文将深入探讨synchronized关键字的工作原理,使用方法以及注意事项,帮助读者更好地理解和使用这一重要的线程同步工具。