<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      為什么volatile不能保證原子性而Atomic可以?

      在上篇《非阻塞同步算法與CAS(Compare and Swap)無鎖算法》中講到在Java中l(wèi)ong賦值不是原子操作,因?yàn)橄葘?2位,再寫后32位,分兩步操作,而AtomicLong賦值是原子操作,為什么?為什么volatile能替代簡單的鎖,卻不能保證原子性?這里面涉及volatile,是java中的一個(gè)我覺得這個(gè)詞在Java規(guī)范中從未被解釋清楚的神奇關(guān)鍵詞,在Sun的JDK官方文檔是這樣形容volatile的:

      The Java programming language provides a second mechanism, volatile fields, that is more convenient than locking for some purposes. A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable.

      意思就是說,如果一個(gè)變量加了volatile關(guān)鍵字,就會告訴編譯器和JVM的內(nèi)存模型:這個(gè)變量是對所有線程共享的、可見的,每次jvm都會讀取最新寫入的值并使其最新值在所有CPU可見。volatile似乎是有時(shí)候可以代替簡單的鎖,似乎加了volatile關(guān)鍵字就省掉了鎖。但又說volatile不能保證原子性(java程序員很熟悉這句話:volatile僅僅用來保證該變量對所有線程的可見性,但不保證原子性)。這不是互相矛盾嗎?

      不要將volatile用在getAndOperate場合,僅僅set或者get的場景是適合volatile的

      不要將volatile用在getAndOperate場合(這種場合不原子,需要再加鎖),僅僅set或者get的場景是適合volatile的

      volatile沒有原子性舉例:AtomicInteger自增

      例如你讓一個(gè)volatile的integer自增(i++),其實(shí)要分成3步:1)讀取volatile變量值到local; 2)增加變量的值;3)把local的值寫回,讓其它的線程可見。這3步的jvm指令為:

      mov    0xc(%r10),%r8d ; Load
      inc    %r8d           ; Increment
      mov    %r8d,0xc(%r10) ; Store
      lock addl $0x0,(%rsp) ; StoreLoad Barrier

      注意最后一步是內(nèi)存屏障。

      什么是內(nèi)存屏障(Memory Barrier)?

      內(nèi)存屏障(memory barrier)是一個(gè)CPU指令。基本上,它是這樣一條指令: a) 確保一些特定操作執(zhí)行的順序; b) 影響一些數(shù)據(jù)的可見性(可能是某些指令執(zhí)行后的結(jié)果)。編譯器和CPU可以在保證輸出結(jié)果一樣的情況下對指令重排序,使性能得到優(yōu)化。插入一個(gè)內(nèi)存屏障,相當(dāng)于告訴CPU和編譯器先于這個(gè)命令的必須先執(zhí)行,后于這個(gè)命令的必須后執(zhí)行。內(nèi)存屏障另一個(gè)作用是強(qiáng)制更新一次不同CPU的緩存。例如,一個(gè)寫屏障會把這個(gè)屏障前寫入的數(shù)據(jù)刷新到緩存,這樣任何試圖讀取該數(shù)據(jù)的線程將得到最新值,而不用考慮到底是被哪個(gè)cpu核心或者哪顆CPU執(zhí)行的。

      內(nèi)存屏障(memory barrier)和volatile什么關(guān)系?上面的虛擬機(jī)指令里面有提到,如果你的字段是volatile,Java內(nèi)存模型將在寫操作后插入一個(gè)寫屏障指令,在讀操作前插入一個(gè)讀屏障指令。這意味著如果你對一個(gè)volatile字段進(jìn)行寫操作,你必須知道:1、一旦你完成寫入,任何訪問這個(gè)字段的線程將會得到最新的值。2、在你寫入前,會保證所有之前發(fā)生的事已經(jīng)發(fā)生,并且任何更新過的數(shù)據(jù)值也是可見的,因?yàn)閮?nèi)存屏障會把之前的寫入值都刷新到緩存。

      volatile為什么沒有原子性?

      明白了內(nèi)存屏障(memory barrier)這個(gè)CPU指令,回到前面的JVM指令:從Load到store到內(nèi)存屏障,一共4步,其中最后一步j(luò)vm讓這個(gè)最新的變量的值在所有線程可見,也就是最后一步讓所有的CPU內(nèi)核都獲得了最新的值,但中間的幾步(從Load到Store)是不安全的,中間如果其他的CPU修改了值將會丟失。下面的測試代碼可以實(shí)際測試voaltile的自增沒有原子性:

          private static volatile long _longVal = 0;
          
      	private static class LoopVolatile implements Runnable {
      		public void run() {
      			long val = 0;
      			while (val < 10000000L) {
      				_longVal++;
      				val++;
      			}
      		}
      	}
      	
      	private static class LoopVolatile2 implements Runnable {
      		public void run() {
      			long val = 0;
      			while (val < 10000000L) {
      				_longVal++;
      				val++;
      			}
      		}
      	}
      	
      	private  void testVolatile(){
      	    Thread t1 = new Thread(new LoopVolatile());
      		t1.start();
      		
      		Thread t2 = new Thread(new LoopVolatile2());
      		t2.start();
      		
              while (t1.isAlive() || t2.isAlive()) {
      	    }
      
      		System.out.println("final val is: " + _longVal);
      	}
      
      Output:-------------
      	
      final val is: 11223828
      final val is: 17567127
      final val is: 12912109

      volatile沒有原子性舉例:singleton單例模式實(shí)現(xiàn)

      這是一段線程不安全的singleton(單例模式)實(shí)現(xiàn),盡管使用了volatile:

      public class wrongsingleton {
      	private static volatile wrongsingleton _instance = null; 
      
      	private wrongsingleton() {}
      
      	public static wrongsingleton getInstance() {
      
      		if (_instance == null) {
      			_instance = new wrongsingleton();
      		}
      
      		return _instance;
      	}
      }

      下面的測試代碼可以測試出是線程不安全的:

      public class wrongsingleton {
      	private static volatile wrongsingleton _instance = null; 
      
      	private wrongsingleton() {}
      
      	public static wrongsingleton getInstance() {
      
      		if (_instance == null) {
      			_instance = new wrongsingleton();
      			System.out.println("--initialized once.");
      		}
      
      		return _instance;
      	}
      }
      
      private static void testInit(){
      		
      		Thread t1 = new Thread(new LoopInit());
      		Thread t2 = new Thread(new LoopInit2());
      		Thread t3 = new Thread(new LoopInit());
      		Thread t4 = new Thread(new LoopInit2());
      		t1.start();
      		t2.start();
      		t3.start();
      		t4.start();
      		
              while (t1.isAlive() || t2.isAlive() || t3.isAlive()|| t4.isAlive()) {
      			
              }
      
      	}
      輸出:有時(shí)輸出"--initialized once."一次,有時(shí)輸出好幾次

      原因自然和上面的例子是一樣的。因?yàn)?strong>volatile保證變量對線程的可見性,但不保證原子性。

      附:正確線程安全的單例模式寫法:

      @ThreadSafe 
      public class SafeLazyInitialization { 
         private static Resource resource; 
         public synchronized static Resource getInstance() { 
            if (resource == null) 
                resource = new Resource(); 
            return resource; 
          } 
      } 

      另外一種寫法:

      @ThreadSafe 
      public class EagerInitialization { 
        private static Resource resource = new Resource(); 
        public static Resource getResource() { return resource; } 
      }

      延遲初始化的寫法:

      @ThreadSafe 
      public class ResourceFactory { 
      	private static class ResourceHolder { 
      		public static Resource resource = new Resource(); 
      	} 
      	public static Resource getResource() { 
      		return ResourceHolder.resource ; 
      	} 
      }

      二次檢查鎖定/Double Checked Locking的寫法(反模式)

      public class SingletonDemo {
      	private static volatile SingletonDemo instance = null;//注意需要volatile
       
      	private SingletonDemo() {	}
       
      	public static SingletonDemo getInstance() {
      		if (instance == null) { //二次檢查,比直接用獨(dú)占鎖效率高
                     synchronized (SingletonDemo .class){
      			        if (instance == null) {
                                     instance = new SingletonDemo (); 
                          }
                   }
      		}
      		return instance;
      	}
      }

      為什么AtomicXXX具有原子性和可見性?

      就拿AtomicLong來說,它既解決了上述的volatile的原子性沒有保證的問題,又具有可見性。它是如何做到的?當(dāng)然就是上文《非阻塞同步算法與CAS(Compare and Swap)無鎖算法》提到的CAS(比較并交換)指令。 其實(shí)AtomicLong的源碼里也用到了volatile,但只是用來讀取或?qū)懭耄娫创a:

      public class AtomicLong extends Number implements java.io.Serializable {
          private volatile long value;
      
          /**
           * Creates a new AtomicLong with the given initial value.
           *
           * @param initialValue the initial value
           */
          public AtomicLong(long initialValue) {
              value = initialValue;
          }
      
          /**
           * Creates a new AtomicLong with initial value {@code 0}.
           */
          public AtomicLong() {
          }

      其CAS源碼核心代碼為:

      int compare_and_swap (int* reg, int oldval, int newval) 
      {
        ATOMIC();
        int old_reg_val = *reg;
        if (old_reg_val == oldval) 
           *reg = newval;
        END_ATOMIC();
        return old_reg_val;
      }

      虛擬機(jī)指令為:

      mov    0xc(%r11),%eax       ; Load
      mov    %eax,%r8d            
      inc    %r8d                 ; Increment
      lock cmpxchg %r8d,0xc(%r11) ; Compare and exchange

      因?yàn)镃AS是基于樂觀鎖的,也就是說當(dāng)寫入的時(shí)候,如果寄存器舊值已經(jīng)不等于現(xiàn)值,說明有其他CPU在修改,那就繼續(xù)嘗試。所以這就保證了操作的原子性。

      ConcurrencyCAS

      posted on 2014-02-19 18:25  Mainz  閱讀(45696)  評論(11)    收藏  舉報(bào)

      導(dǎo)航

      主站蜘蛛池模板: 成全高清在线播放电视剧| 亚洲一区二区乱码精品| 少妇高潮尖叫黑人激情在线| 又粗又硬又黄a级毛片| 欧美日韩精品一区二区视频| 人与禽交av在线播放| 精品国产成人三级在线观看| 一区二区三区无码免费看| 国产国产午夜福利视频| gogo无码大胆啪啪艺术| 夜夜嗨久久人成在日日夜夜| 下面一进一出好爽视频| 久久天天躁狠狠躁夜夜躁2o2o| 中文字幕无码中文字幕有码a| 精品久久久无码中文字幕| 国产午夜精品久久一二区| 无码熟妇αⅴ人妻又粗又大| 久久九九久精品国产免费直播 | 国产精品成人久久电影| 欧美一区二区三区成人久久片 | 免费无码久久成人网站入口| 青草99在线免费观看| 在线精品自拍亚洲第一区| 天堂中文最新版在线官网在线 | 亚洲中国精品精华液| 四虎在线成人免费观看| 日韩亚洲国产激情一区二区| 色偷偷中文在线天堂中文| 亚洲精品天堂一区二区| 天堂国产一区二区三区四区不卡 | 成人特黄特色毛片免费看| 深夜视频国产在线观看| 起碰免费公开97在线视频| 天天爽夜夜爱| 国产18禁黄网站禁片免费视频| 国产精品自产在线观看一| 亚洲成av人片天堂网无码| 绝顶丰满少妇av无码| 临泉县| 日韩有码av中文字幕| 亚洲成人网在线观看|