亚洲欧洲国产欧美一区精品,激情五月亚洲色五月,最新精品国偷自产在线婷婷,欧美婷婷丁香五月天社区

      考試首頁 | 考試用書 | 培訓課程 | 模擬考場 | 考試論壇  
      全國  |             |          |          |          |          |         
        當前位置:計算機等級 > 二級考試 > Java語言程序設計 > 考試輔導 > 文章內容
        

      全國計算機二級考試Java語言程序設計知識點(39)

      中華IT學院   【 】  [ 2016年5月10日 ]

      正確使用 volatile 的模式

        很多并發(fā)性專家事實上往往引導用戶遠離 volatile 變量,因為使用它們要比使用鎖更加容易出錯。然而,如果謹慎地遵循一些良好定義的模式,就能夠在很多場合內安全地使用 volatile 變量。要始終牢記使用 volatile 的限制 —— 只有在狀態(tài)真正獨立于程序內其他內容時才能使用 volatile —— 這條規(guī)則能夠避免將這些模式擴展到不安全的用例。

        模式 #1:狀態(tài)標志

        也許實現(xiàn) volatile 變量的規(guī)范使用僅僅是使用一個布爾狀態(tài)標志,用于指示發(fā)生了一個重要的一次性事件,例如完成初始化或請求停機。

        很多應用程序包含了一種控制結構,形式為 “在還沒有準備好停止程序時再執(zhí)行一些工作”,如清單 2 所示:

        清單 2. 將 volatile 變量作為狀態(tài)標志使用

      volatile boolean shutdownRequested;

      ...

      public void shutdown() { shutdownRequested = true; }

      public void doWork() {

      while (!shutdownRequested) {

      // do stuff

      }

      }

        很可能會從循環(huán)外部調用 shutdown() 方法 —— 即在另一個線程中 —— 因此,需要執(zhí)行某種同步來確保正確實現(xiàn) shutdownRequested 變量的可見性。(可能會從 JMX 偵聽程序、GUI 事件線程中的操作偵聽程序、通過 RMI 、通過一個 Web 服務等調用)。然而,使用 synchronized塊編寫循環(huán)要比使用清單 2 所示的 volatile 狀態(tài)標志編寫麻煩很多。由于 volatile 簡化了編碼,并且狀態(tài)標志并不依賴于程序內任何其他狀態(tài),因此此處非常適合使用 volatile。

        這種類型的狀態(tài)標記的一個公共特性是:通常只有一種狀態(tài)轉換;shutdownRequested 標志從 false 轉換為 true,然后程序停止。這種模式可以擴展到來回轉換的狀態(tài)標志,但是只有在轉換周期不被察覺的情況下才能擴展(從 false 到 true,再轉換到 false)。此外,還需要某些原子狀態(tài)轉換機制,例如原子變量。

        模式 #2:一次性安全發(fā)布(one-time safe publication)

        缺乏同步會導致無法實現(xiàn)可見性,這使得確定何時寫入對象引用而不是原語值變得更加困難。在缺乏同步的情況下,可能會遇到某個對象引用的更新值(由另一個線程寫入)和該對象狀態(tài)的舊值同時存在。(這就是造成著名的雙重檢查鎖定(double-checked-locking)問題的根源,其中對象引用在沒有同步的情況下進行讀操作,產(chǎn)生的問題是您可能會看到一個更新的引用,但是仍然會通過該引用看到不完全構造的對象)。

        實現(xiàn)安全發(fā)布對象的一種技術就是將對象引用定義為 volatile 類型。清單 3 展示了一個示例,其中后臺線程在啟動階段從數(shù)據(jù)庫加載一些數(shù)據(jù)。其他代碼在能夠利用這些數(shù)據(jù)時,在使用之前將檢查這些數(shù)據(jù)是否曾經(jīng)發(fā)布過。

        清單 3. 將 volatile 變量用于一次性安全發(fā)布

      public class BackgroundFloobleLoader {

      public volatile Flooble theFlooble;

      public void initInBackground() {

      // do lots of stuff

      theFlooble = new Flooble(); // this is the only write to theFlooble

      }

      }

      public class SomeOtherClass {

      public void doWork() {

      while (true) {

      // do some stuff...

      // use the Flooble, but only if it is ready

      if (floobleLoader.theFlooble != null)

      doSomething(floobleLoader.theFlooble);

      }

      }

      }

        如果 theFlooble 引用不是 volatile 類型,doWork() 中的代碼在解除對 theFlooble 的引用時,將會得到一個不完全構造的 Flooble。

        該模式的一個必要條件是:被發(fā)布的對象必須是線程安全的,或者是有效的不可變對象(有效不可變意味著對象的狀態(tài)在發(fā)布之后永遠不會被修改)。volatile 類型的引用可以確保對象的發(fā)布形式的可見性,但是如果對象的狀態(tài)在發(fā)布后將發(fā)生更改,那么就需要額外的同步。

        模式 #3:獨立觀察(independent observation)

        安全使用 volatile 的另一種簡單模式是:定期 “發(fā)布” 觀察結果供程序內部使用。例如,假設有一種環(huán)境傳感器能夠感覺環(huán)境溫度。一個后臺線程可能會每隔幾秒讀取一次該傳感器,并更新包含當前文檔的 volatile 變量。然后,其他線程可以讀取這個變量,從而隨時能夠看到最新的溫度值。

        使用該模式的另一種應用程序就是收集程序的統(tǒng)計信息。清單 4 展示了身份驗證機制如何記憶最近一次登錄的用戶的名字。將反復使用lastUser 引用來發(fā)布值,以供程序的其他部分使用。

        清單 4. 將 volatile 變量用于多個獨立觀察結果的發(fā)布

      public class UserManager {

      public volatile String lastUser;

      public boolean authenticate(String user, String password) {

      boolean valid = passwordIsValid(user, password);

      if (valid) {

      User u = new User();

      activeUsers.add(u);

      lastUser = user;

      }

      return valid;

      }

      }

      首頁 1 2 3 尾頁
      分享到:
      本文糾錯】【告訴好友】【打印此文】【返回頂部
      將考試網(wǎng)添加到收藏夾 | 每次上網(wǎng)自動訪問考試網(wǎng) | 復制本頁地址,傳給QQ/MSN上的好友 | 申請鏈接 | 意見留言 TOP
      關于本站  網(wǎng)站聲明  廣告服務  聯(lián)系方式  站內導航  考試論壇
      Copyright © 2007-2013 中華考試網(wǎng)(Examw.com) All Rights Reserved