亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

AtomicInteger原理

tuantuan / 3237人閱讀

摘要:提供這些原子類的目的就是為了解決基本類型操作的非原子性導(dǎo)致在多線程并發(fā)情況下引發(fā)的問(wèn)題。測(cè)試代碼引發(fā)的線程問(wèn)題最終的值為如果是原子操作,那么結(jié)果應(yīng)該就是,反復(fù)運(yùn)行幾次發(fā)現(xiàn)結(jié)果大部分情況下都不是,這也證明了的非原子性在多線程下產(chǎn)生的問(wèn)題。

AtomicInteger的原理

java的并發(fā)原子包里面提供了很多可以進(jìn)行原子操作的類,比如:

AtomicInteger

AtomicBoolean

AtomicLong

AtomicReference

等等,一共分為四類:原子更新基本類型(3個(gè))、原子更新數(shù)組、原子更新引用和原子更新屬性(字段)。、提供這些原子類的目的就是為了解決基本類型操作的非原子性導(dǎo)致在多線程并發(fā)情況下引發(fā)的問(wèn)題。那么非原子性的操作會(huì)引發(fā)什么問(wèn)題呢?下面我們通過(guò)一個(gè)示例來(lái)看一下。

1. i++引發(fā)的問(wèn)題

我們知道基本類型的賦值操作是原子操作,但是類似這種i++的操作并不是原子操作,通過(guò)反編譯代碼我們可以大致了解此操作分為三個(gè)階段:

tp1 = i;  //1
tp2 = tp1 + 1;  //2
i = tp2;  //3

如果有兩個(gè)線程m和n要執(zhí)行i++操作,因?yàn)橹嘏判虻挠绊?,代碼執(zhí)行順序可能會(huì)發(fā)生改變。如果代碼的執(zhí)行順序是m1 - m2 - m3 - n1 - n2 - n3,那么結(jié)果是沒(méi)問(wèn)題的,如果代碼的執(zhí)行順序是m1 - n1 - m2 - n2 - m3 - n3那么很明顯結(jié)果就會(huì)出錯(cuò)。

測(cè)試代碼
package com.wangjun.thread;

public class AtomicIntegerTest {
    
    private static int n = 0;

    public static void main(String[] args) throws InterruptedException {
          //i++引發(fā)的線程問(wèn)題
        Thread t1 = new Thread() {
            public void run() {
                for(int i = 0; i < 1000; i++) {
                    n++;
                }
            }; 
        };
        Thread t2 = new Thread() {
            public void run() {
                for(int i = 0; i < 1000; i++) {
                    n++;
                }
            };
        };
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("最終n的值為:" + n);
    }
}

如果i++是原子操作,那么結(jié)果應(yīng)該就是2000,反復(fù)運(yùn)行幾次發(fā)現(xiàn)結(jié)果大部分情況下都不是2000,這也證明了i++的非原子性在多線程下產(chǎn)生的問(wèn)題。當(dāng)然我們可以通過(guò)加鎖的方式保證操作的原子性,但本文的重點(diǎn)是使用原子類的解決這個(gè)問(wèn)題。

最終n的值為:1367
---
最終n的值為:1243
---
最終n的值為:1380
2. AtomicInteger的原子操作

上面的問(wèn)題可以使用AtomicInteger來(lái)解決,我們更改一下代碼如下:

package com.wangjun.thread;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerTest {
    
    private static AtomicInteger n2 = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
          Thread t1 = new Thread() {
            public void run() {
                for(int i = 0; i < 1000; i++) {
                    n2.incrementAndGet();
                }
            }; 
        };
        Thread t2 = new Thread() {
            public void run() {
                for(int i = 0; i< 1000; i++) {
                    n2.incrementAndGet();
                }
            }
        };
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("最終n2的值為:" + n2.toString());
    }
}

多次運(yùn)行,發(fā)現(xiàn)結(jié)果永遠(yuǎn)是2000,由此可以證明AtomicInteger的操作是原子性的。

最終n2的值為:2000

那么AtomicInteger是通過(guò)什么機(jī)制來(lái)保證原子性的呢?接下來(lái),我們對(duì)源碼進(jìn)行一下分析。

3. AtomicInteger源碼分析 構(gòu)造函數(shù)
private volatile int value;
/*
 * AtomicInteger內(nèi)部聲明了一個(gè)volatile修飾的變量value用來(lái)保存實(shí)際值
 * 使用帶參的構(gòu)造函數(shù)會(huì)將入?yún)①x值給value,無(wú)參構(gòu)造器value默認(rèn)值為0
 */
public AtomicInteger(int initialValue) {
  value = initialValue;
}
自增函數(shù)
import sun.misc.Unsafe;
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
  try {
    valueOffset = unsafe.objectFieldOffset
      (AtomicInteger.class.getDeclaredField("value"));
  } catch (Exception ex) { throw new Error(ex); }
}
/*
 * 可以看到自增函數(shù)中調(diào)用了Unsafe函數(shù)的getAndAddInt方法
 */
public final int incrementAndGet() {
  return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

那么這個(gè)getAndAddInt方法是干嘛的呢,首先來(lái)了解一下Unsafe這個(gè)類。

Unsafe類是在sun.misc包下,不屬于Java標(biāo)準(zhǔn)。但是很多Java的基礎(chǔ)類庫(kù),包括一些被廣泛使用的高性能開(kāi)發(fā)庫(kù)都是基于Unsafe類開(kāi)發(fā)的,比如Netty、Cassandra、Hadoop、Kafka等。Unsafe類在提升Java運(yùn)行效率,增強(qiáng)Java語(yǔ)言底層操作能力方面起了很大的作用。
Unsafe類使Java擁有了像C語(yǔ)言的指針一樣操作內(nèi)存空間的能力,同時(shí)也帶來(lái)了指針的問(wèn)題。過(guò)度的使用Unsafe類會(huì)使得出錯(cuò)的幾率變大,因此Java官方并不建議使用的,官方文檔也幾乎沒(méi)有。
通常我們最好也不要使用Unsafe類,除非有明確的目的,并且也要對(duì)它有深入的了解才行。

再來(lái)說(shuō)Unsafe的getAndAddInt,通過(guò)反編譯可以看到實(shí)現(xiàn)代碼:

/*
 * 其中g(shù)etIntVolatile和compareAndSwapInt都是native方法
 * getIntVolatile是獲取當(dāng)前的期望值
 * compareAndSwapInt就是我們平時(shí)說(shuō)的CAS(compare and swap),通過(guò)比較如果內(nèi)存區(qū)的值沒(méi)有改變,那么就用新值直接給該內(nèi)存區(qū)賦值
 */
public final int getAndAddInt(Object paramObject, long paramLong, int paramInt)
{
  int i;
  do
  {
    i = getIntVolatile(paramObject, paramLong);
  } while (!compareAndSwapInt(paramObject, paramLong, i, i + paramInt));
  return i;
}

incrementAndGet是將自增后的值返回,還有一個(gè)方法getAndIncrement是將自增前的值返回,分別對(duì)應(yīng)++ii++操作。同樣的decrementAndGet和getAndDecrement則對(duì)--ii--操作。

參考:

java的Unsafe類:https://www.cnblogs.com/pkufo...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/69561.html

相關(guān)文章

  • Java多線程學(xué)習(xí)(九)JUC 中的 Atomic 原子類總結(jié)

    摘要:即使是在多個(gè)線程一起執(zhí)行的時(shí)候,一個(gè)操作一旦開(kāi)始,就不會(huì)被其他線程干擾。另外是一個(gè)變量,在內(nèi)存中可見(jiàn),因此可以保證任何時(shí)刻任何線程總能拿到該變量的最新值。 個(gè)人覺(jué)得這一節(jié)掌握基本的使用即可! 本節(jié)思維導(dǎo)圖: showImg(https://segmentfault.com/img/remote/1460000016855442?w=1244&h=657); 1 Atomic 原子類介紹...

    Youngs 評(píng)論0 收藏0
  • 線程池原理淺析

    摘要:線程池主要解決兩個(gè)問(wèn)題一是當(dāng)執(zhí)行大量異步任務(wù)時(shí)線程池能夠提供很好的性能。二是線程池提供了一種資源限制和管理的手段,比如可以限制現(xiàn)成的個(gè)數(shù),動(dòng)態(tài)新增線程等。該方法返回一個(gè)對(duì)象,可指定線程池線程數(shù)量。 什么是線程池? 為了避免頻繁重復(fù)的創(chuàng)建和銷毀線程,我們可以讓這些線程進(jìn)行復(fù)用,在線程池中,總會(huì)有活躍的線程在占用,但是線程池中也會(huì)存在沒(méi)有占用的線程,這些線程處于空閑狀態(tài),當(dāng)有任務(wù)的時(shí)候會(huì)從...

    未東興 評(píng)論0 收藏0
  • 悲觀鎖和樂(lè)觀鎖以及CAS機(jī)制

    摘要:加鎖才能保證線程安全使用之后,不加鎖,也是線程安全的。確保不出現(xiàn)線程安全問(wèn)題。一般在數(shù)據(jù)庫(kù)中使用樂(lè)觀鎖都會(huì)拿版本號(hào)作為對(duì)比值,因?yàn)榘姹咎?hào)會(huì)一直增加,沒(méi)有重復(fù)的,所以不會(huì)出現(xiàn)這個(gè)問(wèn)題。 悲觀鎖: 認(rèn)為每次獲取數(shù)據(jù)的時(shí)候數(shù)據(jù)一定會(huì)被人修改,所以它在獲取數(shù)據(jù)的時(shí)候會(huì)把操作的數(shù)據(jù)給鎖住,這樣一來(lái)就只有它自己能夠操作,其他人都堵塞在那里。 樂(lè)觀鎖: 認(rèn)為每次獲取數(shù)據(jù)的時(shí)候數(shù)據(jù)不會(huì)被別人修改,所以...

    levius 評(píng)論0 收藏0
  • BATJ都愛(ài)問(wèn)的多線程面試題

    摘要:今天給大家總結(jié)一下,面試中出鏡率很高的幾個(gè)多線程面試題,希望對(duì)大家學(xué)習(xí)和面試都能有所幫助。指令重排在單線程環(huán)境下不會(huì)出先問(wèn)題,但是在多線程環(huán)境下會(huì)導(dǎo)致一個(gè)線程獲得還沒(méi)有初始化的實(shí)例。使用可以禁止的指令重排,保證在多線程環(huán)境下也能正常運(yùn)行。 下面最近發(fā)的一些并發(fā)編程的文章匯總,通過(guò)閱讀這些文章大家再看大廠面試中的并發(fā)編程問(wèn)題就沒(méi)有那么頭疼了。今天給大家總結(jié)一下,面試中出鏡率很高的幾個(gè)多線...

    高勝山 評(píng)論0 收藏0
  • AtomicInteger 原子類的作用

    摘要:原子類的作用多線程操作,性能開(kāi)銷太大并不是原子操作。每次比較的是兩個(gè)對(duì)象性能比要好使用時(shí),在高并發(fā)下大量線程會(huì)同時(shí)去競(jìng)爭(zhēng)更新同一個(gè)原子變量,但是由于同時(shí)只有一個(gè)線程的會(huì)成功,所以其他線程會(huì)不斷嘗試自旋嘗試操作,這會(huì)浪費(fèi)不少的資源。 AtomicInteger 原子類的作用 多線程操作,Synchronized 性能開(kāi)銷太大count++并不是原子操作。因?yàn)閏ount++需要經(jīng)過(guò)讀取-...

    MartinDai 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<