最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java CAS底層實(shí)現(xiàn)原理實(shí)例詳解

 更新時(shí)間:2020年01月10日 11:07:36   作者:VincentYew  
這篇文章主要介紹了Java CAS底層實(shí)現(xiàn)原理實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

這篇文章主要介紹了Java CAS底層實(shí)現(xiàn)原理實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

一、CAS(compareAndSwap)的概念

CAS,全稱Compare And Swap(比較與交換),解決多線程并行情況下使用鎖造成性能損耗的一種機(jī)制。

CAS(V, A, B),V為內(nèi)存地址、A為預(yù)期原值,B為新值。如果內(nèi)存地址的值與預(yù)期原值相匹配,那么將該位置值更新為新值。否則,說(shuō)明已經(jīng)被其他線程更新,處理器不做任何操作;無(wú)論哪種情況,它都會(huì)在 CAS 指令之前返回該位置的值。而我們可以使用自旋鎖,循環(huán)CAS,重新讀取該變量再嘗試再次修改該變量,也可以放棄操作。

二、CAS(compareAndSwap)的產(chǎn)生

為什么需要CAS機(jī)制呢?我們先從一個(gè)錯(cuò)誤現(xiàn)象談起。我們經(jīng)常使用volatile關(guān)鍵字修飾某一個(gè)變量,表明這個(gè)變量是全局共享的一個(gè)變量,同時(shí)具有了可見(jiàn)性和有序性。但是卻沒(méi)有原子性。比如說(shuō)一個(gè)常見(jiàn)的操作a++。這個(gè)操作其實(shí)可以細(xì)分成三個(gè)步驟:

(1)從內(nèi)存中讀取a

(2)對(duì)a進(jìn)行加1操作

(3)將a的值重新寫入內(nèi)存中

在單線程狀態(tài)下這個(gè)操作沒(méi)有一點(diǎn)問(wèn)題,但是在多線程中就會(huì)出現(xiàn)各種各樣的問(wèn)題了。因?yàn)榭赡芤粋€(gè)線程對(duì)a進(jìn)行了加1操作,還沒(méi)來(lái)得及寫入內(nèi)存,其他的線程就讀取了舊值。造成了線程的不安全現(xiàn)象。

Volatile關(guān)鍵字可以保證線程間對(duì)于共享變量的可見(jiàn)性可有序性,可以防止CPU的指令重排序(DCL單例),但是無(wú)法保證操作的原子性,所以jdk1.5之后引入CAS利用CPU原語(yǔ)保證線程操作的院子性。

CAS操作由處理器提供支持,是一種原語(yǔ)。原語(yǔ)是操作系統(tǒng)或計(jì)算機(jī)網(wǎng)絡(luò)用語(yǔ)范疇。是由若干條指令組成的,用于完成一定功能的一個(gè)過(guò)程,具有不可分割性,即原語(yǔ)的執(zhí)行必須是連續(xù)的,在執(zhí)行過(guò)程中不允許被中斷。如 Intel 處理器,比較并交換通過(guò)指令的 cmpxchg 系列實(shí)現(xiàn)。

三、CAS(compareAndSwap)的原理探究

CAS的實(shí)現(xiàn)主要在JUC中的atomic包,我們以AtomicInteger類為例:

通過(guò)代碼追溯,可以看出JAVA中的CAS操作都是通過(guò)sun包下Unsafe類實(shí)現(xiàn),而Unsafe類中的方法都是native方法,由JVM本地實(shí)現(xiàn),所以最終的實(shí)現(xiàn)是基于C、C++在操作系統(tǒng)之上操作

Unsafe類,在sun.misc包下,不屬于Java標(biāo)準(zhǔn)。Unsafe類提供一系列增加Java語(yǔ)言能力的操作,如內(nèi)存管理、操作類/對(duì)象/變量、多線程同步等

//var1為CAS操作的對(duì)象,offset為var1某個(gè)屬性的地址偏移值,expected為期望值,var2為要設(shè)置的值,利用JNI來(lái)完成CPU指令的操作
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
public native Object getObjectVolatile(Object var1, long var2);
public native void putObjectVolatile(Object var1, long var2, Object var4);
Hotspot源碼中關(guān)于unsafe的實(shí)現(xiàn)hotspot\src\share\vm\prims\unsafe.cpp
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
 UnsafeWrapper("Unsafe_CompareAndSwapInt");
 oop p = JNIHandles::resolve(obj);根據(jù)偏移量,計(jì)算value的地址。這里的offset就是 AtomaicInteger中的valueOffset
 jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
 return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END\hotspot\src\share\vm\runtime\atomic.cppunsigned Atomic::cmpxchg(unsigned int exchange_value,
             volatile unsigned int* dest, unsigned int compare_value) {
 assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
 return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest,
                    (jint)compare_value);
}根據(jù)操作系統(tǒng)類型調(diào)用不同平臺(tái)下的重載函數(shù),這個(gè)在預(yù)編譯期間編譯器會(huì)決定調(diào)用哪個(gè)平臺(tái)下的重載

可以看到調(diào)用了“Atomic::cmpxchg”方法,“Atomic::cmpxchg”方法在linux_x86和windows_x86的實(shí)現(xiàn)如下

linux_x86底層實(shí)現(xiàn)\hotspot\src\os_cpu\linux_x86\vm\atomic_linux_x86.inline.hpp
inline jint   Atomic::cmpxchg  (jint   exchange_value, volatile jint*   dest, jint   compare_value) {
 int mp = os::is_MP();
 __asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
          : "=a" (exchange_value)
          : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
          : "cc", "memory");
 return exchange_value;
}
windows_x86底層實(shí)現(xiàn)
hotspot\src\os_cpu\windows_x86\vmatomic_linux_x86.inline.hpp
inline jint   Atomic::cmpxchg  (jint   exchange_value, volatile jint*   dest, jint   compare_value) {
 // alternative for InterlockedCompareExchange
 int mp = os::is_MP();
 __asm {
  mov edx, dest
  mov ecx, exchange_value
  mov eax, compare_value
  LOCK_IF_MP(mp)
  cmpxchg dword ptr [edx], ecx
 }
}

總結(jié):根據(jù)資料查詢,其實(shí)CAS底層實(shí)現(xiàn)根據(jù)不同的操作系統(tǒng)會(huì)有不同重載,CAS的實(shí)現(xiàn)離不開處理器的支持。

核心代碼就是一條帶lock 前綴的 cmpxchg 指令,即lock cmpxchg dword ptr [edx], ecx

Atomic::cmpxchg方法解析:

mp是“os::is_MP()”的返回結(jié)果,“os::is_MP()”是一個(gè)內(nèi)聯(lián)函數(shù),用來(lái)判斷當(dāng)前系統(tǒng)是否為多處理器。

如果當(dāng)前系統(tǒng)是多處理器,該函數(shù)返回1。

否則,返回0。

LOCK_IF_MP(mp)會(huì)根據(jù)mp的值來(lái)決定是否為cmpxchg指令添加lock前綴。

如果通過(guò)mp判斷當(dāng)前系統(tǒng)是多處理器(即mp值為1),則為cmpxchg指令添加lock前綴。

否則,不加lock前綴。

這是一種優(yōu)化手段,認(rèn)為單處理器的環(huán)境沒(méi)有必要添加lock前綴,只有在多核情況下才會(huì)添加lock前綴,因?yàn)閘ock會(huì)導(dǎo)致性能下降。cmpxchg是匯編指令,作用是比較并交換操作數(shù)。

四、CAS機(jī)制的優(yōu)缺點(diǎn)

4.1 優(yōu)點(diǎn)

cas是一種樂(lè)觀鎖,而且是一種非阻塞的輕量級(jí)的樂(lè)觀鎖,什么是非阻塞式的呢?其實(shí)就是一個(gè)線程想要獲得鎖,對(duì)方會(huì)給一個(gè)回應(yīng)表示這個(gè)鎖能不能獲得。在資源競(jìng)爭(zhēng)不激烈的情況下性能高,相比synchronized重量鎖,synchronized會(huì)進(jìn)行比較復(fù)雜的加鎖,解鎖和喚醒操作。

4.2 缺點(diǎn)

1)循環(huán)時(shí)間長(zhǎng)開銷大,占用CPU資源

2)只能保證一個(gè)共享變量的原子操作

3)ABA問(wèn)題

4.3 解決ABA問(wèn)題

1)添加版本號(hào)

2)AtomicStampedReference

java并發(fā)包為了解決這個(gè)問(wèn)題,提供了一個(gè)帶有標(biāo)記的原子引用類“AtomicStampedReference”,它可以通過(guò)控制變量值的版本來(lái)保證CAS的正確性。因此,在使用CAS前要考慮清楚“ABA”問(wèn)題是否會(huì)影響程序并發(fā)的正確性,如果需要解決ABA問(wèn)題,改用傳統(tǒng)的互斥同步可能會(huì)比原子類更高效。

五、CAS使用的時(shí)機(jī)

5.1 線程數(shù)較少、等待時(shí)間短可以采用自旋鎖進(jìn)行CAS嘗試拿鎖,較于synchronized高效

5.2 線程數(shù)較大、等待時(shí)間長(zhǎng),不建議使用自旋鎖,占用CPU較高

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 一文帶你學(xué)會(huì)Java事件機(jī)制

    一文帶你學(xué)會(huì)Java事件機(jī)制

    今天小編就為大家分享一篇關(guān)于Java事件機(jī)制的文章,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2021-10-10
  • SpringBoot讀取配置的6種方式

    SpringBoot讀取配置的6種方式

    本文主要介紹了SpringBoot讀取配置的6種方式,主要包括使用默認(rèn)配置、使用application.properties文件、使用application.yml文件、使用@Value注解、使用Environment對(duì)象和使用ConfigurableEnvironment對(duì)象,感興趣的可以了解一下
    2023-08-08
  • Java數(shù)組高級(jí)算法與Arrays類常見(jiàn)操作小結(jié)【排序、查找】

    Java數(shù)組高級(jí)算法與Arrays類常見(jiàn)操作小結(jié)【排序、查找】

    這篇文章主要介紹了Java數(shù)組高級(jí)算法與Arrays類常見(jiàn)操作,結(jié)合實(shí)例形式總結(jié)分析了Java數(shù)組常見(jiàn)的排序算法、查找算法相關(guān)原理、實(shí)現(xiàn)與使用技巧,需要的朋友可以參考下
    2019-03-03
  • 使用Java編寫GUI對(duì)話框的教程

    使用Java編寫GUI對(duì)話框的教程

    這篇文章主要介紹了使用Java編寫GUI對(duì)話框的教程,是Java圖形化編程中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-10-10
  • java中跨域問(wèn)題解決的幾種方式

    java中跨域問(wèn)題解決的幾種方式

    這篇文章主要給大家介紹了關(guān)于java中跨域問(wèn)題解決的幾種方式, 在前后端分離項(xiàng)目中,經(jīng)常會(huì)遇到跨域問(wèn)題,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • SparkSQL使用快速入門

    SparkSQL使用快速入門

    spark SQL是spark的一個(gè)模塊,主要用于進(jìn)行結(jié)構(gòu)化數(shù)據(jù)的處理。它提供的最核心的編程抽象就是DataFrame。這篇文章主要介紹了SparkSQL使用快速入門,需要的朋友可以參考下
    2021-08-08
  • Java數(shù)據(jù)結(jié)構(gòu)二叉樹難點(diǎn)解析

    Java數(shù)據(jù)結(jié)構(gòu)二叉樹難點(diǎn)解析

    樹是一種重要的非線性數(shù)據(jù)結(jié)構(gòu),直觀地看,它是數(shù)據(jù)元素(在樹中稱為結(jié)點(diǎn))按分支關(guān)系組織起來(lái)的結(jié)構(gòu),很象自然界中的樹那樣。樹結(jié)構(gòu)在客觀世界中廣泛存在,如人類社會(huì)的族譜和各種社會(huì)組織機(jī)構(gòu)都可用樹形象表示
    2021-10-10
  • JAVA隨機(jī)打亂數(shù)組順序的方法

    JAVA隨機(jī)打亂數(shù)組順序的方法

    這篇文章主要介紹了JAVA隨機(jī)打亂數(shù)組順序的方法,包含了隨機(jī)數(shù)的應(yīng)用及數(shù)組的排序等操作,是Java操作數(shù)組的典型應(yīng)用,需要的朋友可以參考下
    2014-11-11
  • Spring Boot如何支持嵌入式Servlet容器

    Spring Boot如何支持嵌入式Servlet容器

    這篇文章主要介紹了Spring Boot如何支持嵌入式Servlet容器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Java中的設(shè)計(jì)模式與7大原則歸納整理

    Java中的設(shè)計(jì)模式與7大原則歸納整理

    本篇文章主要對(duì)Java中的設(shè)計(jì)模式如,創(chuàng)建型模式、結(jié)構(gòu)型模式和行為型模式以及7大原則進(jìn)行了歸納整理,需要的朋友可以參考下
    2017-04-04

最新評(píng)論

油尖旺区| 根河市| 蒙阴县| 年辖:市辖区| 丽水市| 乾安县| 蓝田县| 乐陵市| 西藏| 曲水县| 图片| 界首市| 阳新县| 乌拉特后旗| 乌拉特后旗| 腾冲县| 平昌县| 潞西市| 翁源县| 张家港市| 大姚县| 绿春县| 湖南省| 波密县| 保定市| 华阴市| 黄梅县| 陈巴尔虎旗| 炉霍县| 如皋市| 崇信县| 刚察县| 拜泉县| 定边县| 金华市| 红河县| 友谊县| 舒城县| 来宾市| 论坛| 密云县|