在路上

          路上有驚慌,路上有理想

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            28 Posts :: 1 Stories :: 10 Comments :: 0 Trackbacks

          Java 內(nèi)存模型

          JVM系統(tǒng)中存在一個主內(nèi)存(Main Memory),Java中所有變量都儲存在主存中,對于所有線程都是共享的。每條線程都有自己的工作內(nèi)存(Working Memory),工作內(nèi)存中保存的是主存中某些變量的拷貝,線程對所有變量的操作都是在工作內(nèi)存中進(jìn)行,線程之間無法相互直接訪問,變量傳遞均需要通過主存完成。

          模型的規(guī)則:

          1.原子性:保證程序得到成員變量(非局部變量)的值或者是初始值,又或者是某線程修改后的,絕對不是多個線程混亂修改后的。

          2.可見性(共享內(nèi)存的數(shù)據(jù)):什么情況下,寫入成員變量的值對讀取該變量的值是可見的?

               A.寫操作釋放了同步鎖,讀操作獲得了同步鎖

                     原理:釋放鎖的時候強(qiáng)制線程把所使用的工作內(nèi)存中的值刷新到主存,獲得鎖的時候從主存重新裝載值。

                     p.s.鎖只被同步塊和方法中的操作占有,但卻控制了執(zhí)行該操作的線程的所有成員變量。

               B.如果一個成員變量為volatile,那么在寫線程做存儲操作前,寫入這個成員變量的數(shù)據(jù)會在主存中刷新,并對其他線程可見。讀線程每次使用這個成員變量前都要重新從主存讀數(shù)據(jù)。

               C.如果一個線程訪問一個對象的成員變量,讀到的值為初始值或者另一個線程修改后的值。

                  p.s. 不要對引用未完全創(chuàng)建好的對象。

                         如果一個類可以被子類化,那么在構(gòu)造函數(shù)里啟動一個線程是非常危險的

               D.當(dāng)一個線程結(jié)束后,所有的寫入數(shù)據(jù)都會被刷新到主存。

                    p.s.同一個線程的不同方法之間傳遞對象的引用,永遠(yuǎn)不會有可見性問題

             存儲模型保證:如果上面的操作都會發(fā)生,那么一個線程對一個成員變量的更新最終對另一個線程是可見的。

          3.順序化(內(nèi)存操作的順序):什么情況下,一個線程的操作可以是無序的?順序化的問題主要圍繞和讀寫有關(guān)的賦值語句的執(zhí)行順序。

             如果采用同步機(jī)制,那不用多說,順序化可以保證。

             當(dāng)沒有同步機(jī)制時,存儲模型所做的保證是難以相信的。在多線程環(huán)境下,存儲模型是難以保證一定正確的。

            只有當(dāng)滿足下面的三個原則,順序化才得以保證。

             A.從線程執(zhí)行方法的角度看,如果指令都是串行執(zhí)行的,那么順序可以保證

             B.保證同步方法或塊的順序執(zhí)行

             C.使用volatile定義成員變量

          線程執(zhí)行過程中,存儲模型與鎖的關(guān)系:

          (1) 獲取對象的鎖

          (2) 清空工作內(nèi)存數(shù)據(jù), 從主存復(fù)制變量到當(dāng)前工作內(nèi)存, 即同步數(shù)據(jù)

          (3) 執(zhí)行代碼,改變共享變量值

          (4) 將工作內(nèi)存數(shù)據(jù)刷回主存

          (5) 釋放對象的鎖

          最后介紹一下volatile關(guān)鍵字

               volatile定義的成員變量可以保證可見性和順序化,但不保證原子性。比如count++。
               *比如把一個變量聲明為volatile,并不能保證這個變量引用的非volatile數(shù)據(jù)的可見性。比如volatile string[10](數(shù)組)

               正確使用volatile的前提條件

               a.對變量的寫操作不依賴于當(dāng)前值

               b.不要和其他成員變量遵守不變約束。見*處的解釋

              volatile的應(yīng)用

               a.狀態(tài)標(biāo)志

                  volatile boolean shutdownFlag;

                 public void shutdown() { shutdownFlag= true; }
                 public void doWork() {
                 while (!shutdownFlag) {
                  // do something
                   }

               b.假設(shè)一個后臺線程可能會每隔幾秒讀取一次數(shù)據(jù)庫里的合同金額,并更新至 volatile 變量。然后,其他線程可以讀取這個變量,從而隨時能夠看到最新的金額。 比較廣泛應(yīng)用在統(tǒng)計類的系統(tǒng)中。

          參考文檔:

          http://www.cs.umd.edu/~pugh/java/memoryModel/

          http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

          《Java并發(fā)編程:設(shè)計原則與模式》

          posted on 2010-11-03 17:56 阮步兵 閱讀(1457) 評論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 永善县| 故城县| 革吉县| 太和县| 曲麻莱县| 资溪县| 安宁市| 平谷区| 佛教| 泽库县| 玉溪市| 师宗县| 县级市| 江川县| 化州市| 海安县| 新竹市| 呼伦贝尔市| 石楼县| 贵定县| 万年县| 兴安盟| 武冈市| 崇信县| 嵊州市| 上思县| 邮箱| 华容县| 班玛县| 清原| 鄂托克前旗| 固镇县| 雅江县| 微博| 兴化市| 自贡市| 冷水江市| 仙桃市| 泸溪县| 金坛市| 明溪县|