1. gzyueqian
      18529173453
      首頁 > 新聞中心 > > 正文

      破除java神話之原子操作都是線程安全的

      更新時(shí)間: 2007-06-04 13:22:31來源: 粵嵌教育瀏覽量:596


        java中原子操作是線程安全的論調(diào)經(jīng)常被提到。根據(jù)定義,原子操作是不會(huì)被打斷地的操作,因此被認(rèn)為是線程安全的。實(shí)際上有一些原子操作不一定是線程安全的。
        
        這個(gè)問題出現(xiàn)的原因是盡量減少在代碼中同步關(guān)鍵字。同步會(huì)損害性能,雖然這個(gè)損失因JVM不同而不同。另外,在現(xiàn)代的JVM中,同步的性能正在逐步提高。盡管如此,使用同步仍然是有性能代價(jià)的,并且程序員永遠(yuǎn)會(huì)盡力提高他們的代碼的效率,因此這個(gè)問題就延續(xù)了下來。
        
        在java中,32位或者更少位數(shù)的賦值是原子的。在一個(gè)32位的硬件平臺(tái)上,除了double和long型的其它原始類型通常都是使用32位進(jìn)行表示,而double和long通常使用64位表示。另外,對(duì)象引用使用本機(jī)指針實(shí)現(xiàn),通常也是32位的。對(duì)這些32位的類型的操作是原子的。
        這些原始類型通常使用32位或者64位表示,這又引入了另一個(gè)小小的神話:原始類型的大小是由語言保證的。這是不對(duì)的。java語言保證的是原始類型的表數(shù)范圍而非JVM中的存儲(chǔ)大小。因此,int型總是有相同的表數(shù)范圍。在一個(gè)JVM上可能使用32位實(shí)現(xiàn),而在另一個(gè)JVM上可能是64位的。在此再次強(qiáng)調(diào):在所有平臺(tái)上被保證的是表數(shù)范圍,32位以及更小的值的操作是原子的。
        
        那么,原子操作在什么情況下不是線程安全的?主要的一點(diǎn)是他們也許確實(shí)是線程安全的,但是這沒有被保證!java線程允許線程在自己的內(nèi)存區(qū)保存變量的副本。允許線程使用本地的私有拷貝進(jìn)行工作而非每次都使用主存的值是為了提高性能。考慮下面的類:
        
        class RealTimeClock
        {
         private int clkID;
         public int clockID()
         {
         return clkID;
         }
         public void setClockID(int id)
         {
         clkID = id;
         }
        //...
        }
        
        現(xiàn)在考慮RealTimeClock的一個(gè)實(shí)例以及兩個(gè)線程同時(shí)調(diào)用setClockID和clockID,并發(fā)生以下的事件序列:
        
        T1 調(diào)用setClockID(5)
        T1將5放入自己的私有工作內(nèi)存
        T2調(diào)用setClockID(10)
        T2將10放入自己的私有工作內(nèi)存
        T1調(diào)用clockID,它返回5
        5是從T1的私有工作內(nèi)存返回的
        
        對(duì)clockI的調(diào)用應(yīng)該返回10,因?yàn)檫@是被T2設(shè)置的,然而返回的是5,因?yàn)樽x寫操作是對(duì)私有工作內(nèi)存的而非主存。賦值操作當(dāng)然是原子的,但是因?yàn)镴VM允許這種行為,因此線程安全不是一定的,同時(shí),JVM的這種行為也不是被保證的。
        
        兩個(gè)線程擁有自己的私有拷貝而不和主存一致。如果這種行為出現(xiàn),那么私有本機(jī)變量和主存一致必須在以下兩個(gè)條件下:
        
        1、變量使用volatile聲明
        2、被訪問的變量處于同步方法或者同步塊中
        
        如果變量被聲明為volatile,在每次訪問時(shí)都會(huì)和主存一致。這個(gè)一致性是由java語言保證的,并且是原子的,即使是64位的值。(注意很多JVM沒有正確的實(shí)現(xiàn)volatile關(guān)鍵字。你可以在www.javasoft.com找到更多的信息。)另外,如果變量在同步方法或者同步塊中被訪問,當(dāng)在方法或者塊的入口處獲得鎖以及方法或者塊退出時(shí)釋放鎖是變量被同步。
        使用任何一種方法都可以保證ClockID返回10,也就是正確的值。變量訪問的頻度不同則你的選擇的性能不同。如果你更新很多變量,那么使用volatile可能比使用同步更慢。記住,如果變量被聲明為volatile,那么在每次訪問時(shí)都會(huì)和主存一致。與此對(duì)照,使用同步時(shí),變量只在獲得鎖和釋放鎖的時(shí)候和主存一致。但是同步使得代碼有較少的并發(fā)性。
        
        如果你更新很多變量并且不想有每次訪問都和主存進(jìn)行同步的損失或者你因?yàn)槠渌脑蛳肱懦l(fā)性時(shí)可以考慮使用同步。

      免費(fèi)預(yù)約試聽課

      亚洲另类欧美综合久久图片区_亚洲中文字幕日产无码2020_欧美日本一区二区三区桃色视频_亚洲AⅤ天堂一区二区三区

      
      

      1. 最新精品国偷自产手机在线 | 中文字幕高清视频在线不卡 | 日本深夜福利在线观看不卡高清 | 亚洲第一在线精品 | 真实国产乱子伦高清对白 | 天天爽夜夜操一区二区 |