日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java Review - 并发编程_原子操作类原理剖析

發(fā)布時(shí)間:2025/3/21 java 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java Review - 并发编程_原子操作类原理剖析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 概述
  • 原子變量操作類
  • 主要方法
    • incrementAndGet 、decrementAndGet 、getAndIncrement、getAndDecrement
    • boolean compareAndSet(long expect, long update)
  • 小Demo
  • 小結(jié)


概述

JUC包提供了一系列的原子性操作類,這些類都是使用非阻塞算法CAS實(shí)現(xiàn)的,相比使用鎖實(shí)現(xiàn)原子性操作這在性能上有很大提高。

由于原子性操作類的原理都大致相同,我們以AtomicLong類的實(shí)現(xiàn)原理為例,并探討JDK8新增的 LongAdder和LongAccumulator類的原理

原子變量操作類

JUC并發(fā)包中包含有AtomicInteger、AtomicLong和AtomicBoolean等原子性操作類

AtomicLong是原子性遞增或者遞減類,其內(nèi)部使用Unsafe來(lái)實(shí)現(xiàn),我們看下面的代碼

package java.util.concurrent.atomic; import java.util.function.LongUnaryOperator; import java.util.function.LongBinaryOperator; import sun.misc.Unsafe;/*** @since 1.5* @author Doug Lea*/ public class AtomicLong extends Number implements java.io.Serializable {private static final long serialVersionUID = 1927816293512124184L;// 1 獲取Unsafe實(shí)例private static final Unsafe unsafe = Unsafe.getUnsafe();// 2 存放變量的偏移量private static final long valueOffset;/*** Records whether the underlying JVM supports lockless* compareAndSwap for longs. While the Unsafe.compareAndSwapLong* method works in either case, some constructions should be* handled at Java level to avoid locking user-visible locks.*/// 3 判斷JVM是否支持Long類型的CASstatic final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();/*** Returns whether underlying JVM supports lockless CompareAndSet* for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.*/private static native boolean VMSupportsCS8();static {try {// 4 獲取value在AtomicLong中的偏移量valueOffset = unsafe.objectFieldOffset(AtomicLong.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}// 5 實(shí)際變量值private volatile long value;/*** Creates a new AtomicLong with the given initial value.** @param initialValue the initial value*/public AtomicLong(long initialValue) {value = initialValue;}............................}
  • 代碼(1)通過(guò)Unsafe.getUnsafe()方法獲取到Unsafe類的實(shí)例

    為何能通過(guò)Unsafe.getUnsafe()方法獲取到Unsafe類的實(shí)例?其實(shí)這是因?yàn)锳tomicLong類也是在rt.jar包下面的,AtomicLong類就是通過(guò)BootStarp類加載器進(jìn)行加載的。

  • 代碼(5)中的value被聲明為volatile的,這是為了在多線程下保證內(nèi)存可見性,value是具體存放計(jì)數(shù)的變量。

  • 代碼(2)(4)獲取value變量在AtomicLong類中的偏移量。


主要方法

incrementAndGet 、decrementAndGet 、getAndIncrement、getAndDecrement

【JDK8+】

//(6)調(diào)用 Insafe方法,原子性設(shè)置 value值為原始值+1,返回值為遞增后的值public final long incrementAndGet() {return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;}//(7)調(diào)用 unsafe方法,原子性設(shè)置va1ue值為原始值-1,返回值為遞減之后的值public final long decrementAndGet() {return unsafe.getAndAddLong(this, valueOffset, -1L) - 1L;} //(8)調(diào)用 unsafe方法,原子性設(shè)置va1ue值為原始值+1,返回值為原始值 public final long getAndIncrement() {return unsafe.getAndAddLong(this, valueOffset, 1L);} //(9)調(diào)用 unsafe方法,原子性設(shè)置va1ue值為原始值-1,返回值為原始值public final long getAndDecrement() {return unsafe.getAndAddLong(this, valueOffset, -1L);}

我們可以發(fā)現(xiàn)這幾個(gè)方法內(nèi)部都是通過(guò)調(diào)用Unsafe的getAndAddLong方法來(lái)實(shí)現(xiàn)操作,這個(gè)函數(shù)是個(gè)原子性操作。

第一個(gè)參數(shù)是AtomicLong實(shí)例的引用, 第二個(gè)參數(shù)是value變量在AtomicLong中的偏移值, 第三個(gè)參數(shù)是要設(shè)置的第二個(gè)變量的值 。

getAndIncrement方法在JDK 7中的實(shí)現(xiàn)邏輯為

public final long getAndIncrement(){while(true){long current=get();long next= current + 1;if (compareAndSet(current, next))return current} }

在如上代碼中,每個(gè)線程是先拿到變量的當(dāng)前值(由于value是volatile變量,所以這里拿到的是最新的值),然后在工作內(nèi)存中對(duì)其進(jìn)行增1操作,而后使用CAS修改變量的值。如果設(shè)置失敗,則循環(huán)繼續(xù)嘗試,直到設(shè)置成功。

而JDK 8中的邏輯為

unsafe.getAndAddLong(this, valueOffset, -1L); 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;}

可以看到,JDK 7的AtomicLong中的循環(huán)邏輯已經(jīng)被JDK 8中的原子操作類UNsafe內(nèi)置了,之所以內(nèi)置應(yīng)該是考慮到這個(gè)函數(shù)在其他地方也會(huì)用到,而內(nèi)置可以提高復(fù)用性。


boolean compareAndSet(long expect, long update)

/*** Atomically sets the value to the given updated value* if the current value {@code ==} the expected value.** @param expect the expected value* @param update the new value* @return {@code true} if successful. False return indicates that* the actual value was not equal to the expected value.*/public final boolean compareAndSet(long expect, long update) {return unsafe.compareAndSwapLong(this, valueOffset, expect, update);}

我們可以看到內(nèi)部還是調(diào)用了unsafe.compareAndSwapLong方法。如果原子變量中的value值等于expect,則使用update值更新該值并返回true,否則返回false。


小Demo

線程使用AtomicLong統(tǒng)計(jì)0的個(gè)數(shù)的例子

import java.util.concurrent.atomic.AtomicLong;/*** @author 小工匠* @version 1.0* @description: TODO* @date 2021/11/30 22:52* @mark: show me the code , change the world*/ public class AtomicLongTest {//(10)創(chuàng)建Long型原子計(jì)數(shù)器private static AtomicLong atomicLong = new AtomicLong();//(11)創(chuàng)建數(shù)據(jù)源private static Integer[] arrayOne = new Integer[]{0, 1, 2, 3, 0, 5, 6, 0, 56, 0};private static Integer[] arrayTwo = new Integer[]{10, 1, 2, 3, 0, 5, 6, 0, 56, 0};public static void main(String[] args) throws InterruptedException {//(12)線程one統(tǒng)計(jì)數(shù)組arrayOne中0的個(gè)數(shù)Thread threadOne = new Thread(() -> {int size = arrayOne.length;for (int i = 0; i < size; ++i) {if (arrayOne[i].intValue() == 0) {atomicLong.incrementAndGet();}}});//(13)線程two統(tǒng)計(jì)數(shù)組arrayTwo中0的個(gè)數(shù)Thread threadTwo = new Thread(() -> {int size = arrayTwo.length;for (int i = 0; i < size; ++i) {if (arrayTwo[i].intValue() == 0) {atomicLong.incrementAndGet();}}});//(14)啟動(dòng)子線程threadOne.start();threadTwo.start();//(15)等待線程執(zhí)行完畢threadOne.join();threadTwo.join();System.out.println("count 0:" + atomicLong.get());}}


兩個(gè)線程各自統(tǒng)計(jì)自己所持?jǐn)?shù)據(jù)中0的個(gè)數(shù),每當(dāng)找到一個(gè)0就會(huì)調(diào)用AtomicLong的原子性遞增方法


小結(jié)

在沒有原子類的情況下,實(shí)現(xiàn)計(jì)數(shù)器需要使用一定的同步措施,比如使用synchronized關(guān)鍵字等,但是這些都是阻塞算法,對(duì)性能有一定損耗,而這里我們介紹的這些原子操作類都使用CAS非阻塞算法,性能更好。

但是在高并發(fā)情況下AtomicLong還會(huì)存在性能問題。JDK 8提供了一個(gè)在高并發(fā)下性能更好的LongAdder類,且聽下篇分解

總結(jié)

以上是生活随笔為你收集整理的Java Review - 并发编程_原子操作类原理剖析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。