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

Java多線程CAS操作原理代碼實例解析

 更新時間:2020年07月25日 09:46:55   作者:AmourLee  
這篇文章主要介紹了Java多線程CAS操作原理代碼實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

CAS操作號稱無鎖優(yōu)化,也叫作自旋;對于一些常見的操作需要加鎖,然后jdk就提供了一些以Atomic開頭的類,這些類內(nèi)部自動帶了鎖,當(dāng)然這里的鎖并非是用synchronized來實現(xiàn)的,而是通過CAS操作來實現(xiàn)的;

一、下面是 AtomicInteger 的使用:

package com.designmodal.design.juc01;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author D-L
 * @Classname T03_AtomicInteger
 * @Version 1.0
 * @Description 使用 AtomicInteger 類解決常見的 多線程count++
 *        其內(nèi)部使用了CAS操作來保證原子性 但是不能保證多個方法連續(xù)調(diào)用都是原子性
 * @Date 2020/7/21 0:35
 */
public class T03_AtomicInteger {
  //使用AtomicInteger類
  AtomicInteger count = new AtomicInteger(0);

  public void m(){
    for (int i = 0; i < 10000; i++) {
      //等同于 在 count++ 上加鎖
      count.incrementAndGet();
    }
  }

  public static void main(String[] args) {
    T03_AtomicInteger t = new T03_AtomicInteger();
    List<Thread> threads = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
      threads.add(new Thread(t::m , "Thread" + i));
    }
    threads.forEach((o) -> o.start());
    threads.forEach(o ->{
      try {
        o.join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    });

    System.out.println(t.count);
  }
}

二、當(dāng)然達(dá)到使用的級別很簡單,看一下API就好了,通過上面的小程序,下面主要來聊一聊原理:

1、通過源碼分析AtomicInteger

首先小程序中定義了一個 AtomicInteger 類型的變量count;

 AtomicInteger count = new AtomicInteger(0);
 public void add(){
  count.incrementAndGet();
 }

調(diào)用了AtomicInteger類中incrementAndGet();

/**
   * Atomically increments by one the current value.
   *
   * @return the updated value
   */
  public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
  }

調(diào)用unsafe類中的 getAndAddInt(Object var1, long var2, int var4)方法;

public native int getIntVolatile(Object var1, long var2);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);


 public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
      var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
  }

這里通過以上三步的操作,最終會進(jìn)入Unsafe類這里調(diào)用的 compareAndSwapInt 意思就是比較然后交換,通過一個while循環(huán),在這里轉(zhuǎn)呀轉(zhuǎn),直到修改成功;

CAS(compareAndSwap)(比較并交換):原來想改變的值為0 ,現(xiàn)在想修改成1 ,這里想做到線程安全就必須要加synchronized,現(xiàn)在想用另外一種方式來替換加鎖的方法,就是所謂的CAS操作;你可以把它想象成擁有三個參數(shù)的方法cas(V , Expected , NewValue); 第一個參數(shù)V是你要改的那個值,Expected第二個參數(shù)是你期望當(dāng)前的值是多少(也就是如果沒有線程修改的時,這個值應(yīng)該是多少,如果不是期望值那就證明有別的線程修改過),NewValue是要設(shè)置的新值;

上圖簡單模擬了CAS操作的過程,當(dāng)線程1和線程2同時讀取了共享變量count = 0;在線程1修改的過程中,線程2已經(jīng)將count值修改為1,那么在線程1修改的時候發(fā)現(xiàn)Expected值和V已經(jīng)匹配不上了,證明已經(jīng)有線程快我一步將count值改了(可能這里并發(fā)量大的時候已經(jīng)有n多個線程已經(jīng)修改過了),怎么辦呢?那我只能將我的期望值修改成V的值、newValue 在這基礎(chǔ)上加1,然后繼續(xù)在這自旋操作,直到修改成功,這就是自旋操作;

2、Unsafe類(java并發(fā)包底層實現(xiàn)的核心)

CAS操作不需要加鎖是如何做到的呢?原因就在于Unsafe這個類,這個類除了你使用反射之外,你是不能夠直接使用的,這里不能使用的原因和ClassLoader有關(guān)系,所有AtomicXXX 類內(nèi)部都是CompareAndSwap / CompareAndSet(新版jdk),這個類中存在好多native方法;

Unsafe類使Java擁有了像C語言的指針一樣操作內(nèi)存空間的能力,一旦能夠直接操作內(nèi)存,這也就意味著(1)不受JVM管理,也就意味著無法被GC,需要我們手動GC,稍有不慎就會出現(xiàn)內(nèi)存泄漏。(2)Unsafe的不少方法中必須提供原始地址(內(nèi)存地址)和被替換對象的地址,偏移量要自己計算,一旦出現(xiàn)問題就是JVM崩潰級別的異常,會導(dǎo)致整個JVM實例崩潰,表現(xiàn)為應(yīng)用程序直接crash掉。(3)直接操作內(nèi)存,也意味著其速度更快,在高并發(fā)的條件之下能夠很好地提高效率。

CAS:CompareAndSwap,內(nèi)存偏移地址(var2),預(yù)期值(var4),新值(var5)。如果變量在當(dāng)前時刻的值和預(yù)期值expected相等,嘗試將變量的值更新為新值(var5)。如果更新成功,返回true;否則,返回false。

/**
   * CAS操作 :Unsafe類中的本地方法 由于Java語言無法訪問操作系統(tǒng)底層信息(比如:底層硬件設(shè)備等),
   * 這時候就需要借助C C++語言來完成了
   * @param var1 對象
   * @param var2 偏移量
   * @param var4 期望值
   * @param var5 新值
   * @return 修改成功返回true 失敗返回false
   */
  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);

三、CAS操作帶來的ABA問題

ABA問題說白了就是在線程進(jìn)行CAS操作過程中有多個線程對這個共享變量進(jìn)行修改,有加有減,兜兜轉(zhuǎn)轉(zhuǎn)又回到起始值,這時該線程渾然不知;打個不恰當(dāng)?shù)谋扔鳎哼@個過程就好像你前女友跟你分手以后,在時隔一年之后又找你復(fù)合來了,說兜兜轉(zhuǎn)轉(zhuǎn)還是覺得你好,在此期間你前女友已經(jīng)換了幾個男朋友你卻渾然不知,那個好看的她穿著你喜歡的小短裙,扎著清純的馬尾辮又回來,好了言歸正傳,意思就是結(jié)果是你期望的,可是這個值是經(jīng)過很多版本的。

下面簡單模擬ABA操作圖:

如何解決ABA問題呢?

如果是int類型,最終的值也是你期望的,真的是沒有所謂,你也不用去糾結(jié)這問題;如果你確實就想管一管,那就加一個版本號,做一次修改操作加一,比較檢查時連帶版本號一起檢查。

基礎(chǔ)類型:沒有必要管,對你真的沒有所謂;

引用類型:就像是你女朋友和你分手之后又復(fù)合,中間經(jīng)歷了多少個男朋友,這個是有所謂的,這時可以通過加版本號來解決;

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

相關(guān)文章

  • Java異步處理機(jī)制實例詳解

    Java異步處理機(jī)制實例詳解

    本文涉及Java編程中異步處理機(jī)制的簡單介紹和一個相關(guān)實例,相信通過這篇文章,大家能對異步處理有更多的了解。
    2017-09-09
  • SpringBoot項目使用MDC給日志增加唯一標(biāo)識的實現(xiàn)步驟

    SpringBoot項目使用MDC給日志增加唯一標(biāo)識的實現(xiàn)步驟

    本文介紹了如何在SpringBoot項目中使用MDC(Mapped?Diagnostic?Context)為日志增加唯一標(biāo)識,以便于日志追蹤,通過創(chuàng)建日志攔截器、配置攔截器以及修改日志配置文件,可以實現(xiàn)這一功能,文章還提供了源碼地址,方便讀者學(xué)習(xí)和參考,感興趣的朋友一起看看吧
    2025-03-03
  • Java volatile關(guān)鍵字原理剖析與實例講解

    Java volatile關(guān)鍵字原理剖析與實例講解

    volatile是Java提供的一種輕量級的同步機(jī)制,Java?語言包含兩種內(nèi)在的同步機(jī)制:同步塊(或方法)和?volatile?變量,本文將詳細(xì)為大家總結(jié)Java volatile關(guān)鍵字,通過詳細(xì)的代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • Java GUI制作簡單的管理系統(tǒng)

    Java GUI制作簡單的管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java GUI制作簡單的管理系統(tǒng)的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java實現(xiàn)身份證號碼驗證源碼示例分享

    Java實現(xiàn)身份證號碼驗證源碼示例分享

    本篇文章主要介紹了Java實現(xiàn)身份證號碼驗證源碼示例分享,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 使用DevOps開源利器開發(fā)部署Hygieia平臺

    使用DevOps開源利器開發(fā)部署Hygieia平臺

    這篇文章主要為大家介紹了使用DevOps開源利器開發(fā)部署Hygieia平臺的實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職?加薪
    2022-03-03
  • Java反射機(jī)制在Spring IOC中的應(yīng)用詳解

    Java反射機(jī)制在Spring IOC中的應(yīng)用詳解

    這篇文章主要介紹了Java反射機(jī)制在Spring IOC中的應(yīng)用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Springboot?hibernate-validator?6.x快速校驗示例代碼

    Springboot?hibernate-validator?6.x快速校驗示例代碼

    這篇文章主要介紹了Springboot?hibernate-validator?6.x校驗,本文以6.2.1.Final版本為例解決了log4j版本的漏洞問題,通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12
  • 詳細(xì)解讀Java的Lambda表達(dá)式

    詳細(xì)解讀Java的Lambda表達(dá)式

    這篇文章主要介紹了詳細(xì)解讀Java的Lambda表達(dá)式,lambda?表達(dá)式?是Java?8新加入的新特性,它在Java中是引入了函數(shù)式編程這一概念,需要的朋友可以參考下
    2023-04-04
  • Java中如何讀取和寫入zip文件問題

    Java中如何讀取和寫入zip文件問題

    這篇文章主要介紹了Java中如何讀取和寫入zip文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06

最新評論

广东省| 即墨市| 内丘县| 略阳县| 弥勒县| 南乐县| 富裕县| 阿克苏市| 资中县| 潢川县| 上犹县| 怀柔区| 化州市| 漯河市| 休宁县| 台江县| 博客| 亚东县| 泰安市| 安顺市| 万荣县| 福州市| 宾阳县| 中阳县| 广昌县| 兴业县| 齐齐哈尔市| 南江县| 通江县| 岳池县| 河池市| 贵港市| 赤水市| 洪雅县| 黔西县| 邵东县| 宝坻区| 安新县| 斗六市| 台北县| 易门县|