volatile不能保證原子性及其解決方案


volatile不能保證原子性及其解決方案
volatile類型的變量有三個特點
1:可見性
2:不能保證原子性
3:禁止重排

2、不能保證原子性
或者說最終一致性不能得到保證,我們看如下案例

import java.util.concurrent.TimeUnit;
class MyData{//我們創建一個資源類
    volatile int number = 0;
    public void numberPlusPlus() {
        number++;
    }
}
public class VolatileDemo {    
    public static void main(String[] args) {
        MyData myData = new MyData();    
            for (int i = 1; i <=20; i++) {
                new Thread(()->{//每次循環新建一個線程,一共創建20個線程
                    for (int j = 1; j <=1000; j++) {
                        myData.numberPlusPlus();
              //每一個線程都使number自加1000次 } },String.valueOf(i)).start(); }
try { TimeUnit.SECONDS.sleep(3);
          //設置3秒的時長 }
catch (Exception e) { // TODO: handle exception } while (Thread.activeCount()>2) {
        //判斷大於兩個活躍線程,是因為,一個Java程序,還有主線程和gc線程 Thread.yield(); } System.out.println(Thread.currentThread().getName()
+myData.number); } }

 



很容易理解的一個程序,按照正常的想法來看20個線程,每個使number自加1000次
應該的到20000的結果
但是此程序實際運行結果則不然,基本運行的都不是20000(偶然情況下,也可以是,但是概率很小),這是因為多線程的情況下,各個線程搶占資源,對數據進行讀寫,有一部分是同時進行的看下圖

比如說 a線程此時拿到了number的值為0,b線程也拿到了number的值為0,他倆一起返回各自的內存工作區,進行自加操作,此時a線程中的number變為1,然后返回主內存中把主內存的number的值改寫為1。b線程中的number在自己的內存工作區中,b線程把number自加為1,再去主內存中把number的值改寫為1。
此時很明顯,number自加了兩次,卻最后的值為1
這就是多線程中存在的一個問題,但是肯定萬能的程序員肯定是有解決辦法的
這里給大家提供兩種
1:加鎖synchronized(不推薦因為不是最優的辦法)
public ynchronized void numberPlusPlus() {
number++;
}
2:AtomicInteger類型數據
我的理解是原子integer類,這個類型的數據可以保證各個線程操作的是同一個數據,一個線程對該數據進行操作時,其他線程不能操作,這就保證的原子性或者說最終一致性
AtomicInteger atomicInteger = new AtomicInteger();
public void addAtomicInteger() {
atomicInteger.getAndIncrement();
//AtomicInteger類中有很多的方法
//此時調用的方法表示自加
//當然還有很多的方法,這就需要各位大牛自己研究了
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM