20190709原子操作類AtomicInteger

1、原子操作類AtomicInteger

? ??對于Java中的運(yùn)算操作,例如自增或自減,若沒有進(jìn)行額外的同步操作,在多線程環(huán)境下就是線程不安全的。num++解析為num=num+1,明顯,這個操作不具備原子性,多線程并發(fā)共享這個變量時必然會出現(xiàn)問題,測試代碼如下:

public class AtomicIntegerTest {

? ? private static final int THREADS_CONUT = 20;

? ? public static int count = 0;

? ? public static void increase() {

? ? ? ? count++;

? ? }

? ? public static void main(String[] args) {

? ? ? ? Thread[] threads = new Thread[THREADS_CONUT];

? ? ? ? for (int i = 0; i < THREADS_CONUT; i++) {

? ? ? ? ? ? threads[i] = new Thread(new Runnable() {

? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? public void run() {

? ? ? ? ? ? ? ? ? ? for (int i = 0; i < 1000; i++) {

? ? ? ? ? ? ? ? ? ? ? ? increase();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });

? ? ? ? ? ? threads[i].start();

? ? ? ? }

? ? ? ? while (Thread.activeCount() > 1) {

? ? ? ? ? ? Thread.yield();

? ? ? ? }

? ? ? ? System.out.println(count);

? ? }

}

------------------------------------------------------------------------------------------------------

這里運(yùn)行了20個線程,每個線程對count變量進(jìn)行1000此自增操作,如果上面這段代碼能夠正常并發(fā)的話,最后的結(jié)果應(yīng)該是20000才對,但實際結(jié)果卻發(fā)現(xiàn)每次運(yùn)行的結(jié)果都不相同,都是一個小于20000的數(shù)字。這是為什么呢?

要是換成volatile修飾count變量呢?

順帶說下volatile關(guān)鍵字很重要的兩個特性:

1、保證變量在線程間可見,對volatile變量所有的寫操作都能立即反應(yīng)到其他線程中,換句話說,volatile變量在各個線程中是一致的(得益于java內(nèi)存模型—"先行發(fā)生原則");

2、禁止指令的重排序優(yōu)化;

那么換成volatile修飾count變量后,會有什么效果呢? 試一試:

public class AtomicIntegerTest {

? ? private static final int THREADS_CONUT = 20;

? ? public static volatile int count = 0;

? ? public static void increase() {

? ? ? ? count++;

? ? }

? ? public static void main(String[] args) {

? ? ? ? Thread[] threads = new Thread[THREADS_CONUT];

? ? ? ? for (int i = 0; i < THREADS_CONUT; i++) {

? ? ? ? ? ? threads[i] = new Thread(new Runnable() {

? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? public void run() {

? ? ? ? ? ? ? ? ? ? for (int i = 0; i < 1000; i++) {

? ? ? ? ? ? ? ? ? ? ? ? increase();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });

? ? ? ? ? ? threads[i].start();

? ? ? ? }

? ? ? ? while (Thread.activeCount() > 1) {

? ? ? ? ? ? Thread.yield();

? ? ? ? }

? ? ? ? System.out.println(count);

? ? }

}

---------------------

結(jié)果似乎又失望了,測試結(jié)果和上面的一致,每次都是輸出小于20000的數(shù)字。這又是為什么么? 上面的論據(jù)是正確的,也就是上面標(biāo)紅的內(nèi)容,但是這個論據(jù)并不能得出"基于volatile變量的運(yùn)算在并發(fā)下是安全的"這個結(jié)論,因為核心點(diǎn)在于java里的運(yùn)算(比如自增)并不是原子性的。

用了AtomicInteger類后會變成什么樣子呢?

把上面的代碼改造成AtomicInteger原子類型,先看看效果

public class AtomicIntegerTest {

? ? private static final int THREADS_CONUT = 20;

? ? public static AtomicInteger count = new AtomicInteger(0);

? ? public static void increase() {

? ? ? ? count.incrementAndGet();

? ? }

? ? public static void main(String[] args) {

? ? ? ? Thread[] threads = new Thread[THREADS_CONUT];

? ? ? ? for (int i = 0; i < THREADS_CONUT; i++) {

? ? ? ? ? ? threads[i] = new Thread(new Runnable() {

? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? public void run() {

? ? ? ? ? ? ? ? ? ? for (int i = 0; i < 1000; i++) {

? ? ? ? ? ? ? ? ? ? ? ? increase();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });

? ? ? ? ? ? threads[i].start();

? ? ? ? }

? ? ? ? while (Thread.activeCount() > 1) {

? ? ? ? ? ? Thread.yield();

? ? ? ? }

? ? ? ? System.out.println(count);

? ? }

}

---------------------

結(jié)果每次都輸出20000,程序輸出了正確的結(jié)果,這都歸功于AtomicInteger.incrementAndGet()方法的原子性。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容