熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java理論與實踐: 描繪線程安全性[1]

2022-06-13   來源: Java高級技術 

  定義線程安全 style=COLOR: # href=http://safeitcom/ target=_blank>安全性

  明確定義線程安全性出人意料地困難大多數定義看上去完全是自我循環快速搜索一下 Google可以找到以下關於線程安全代碼的典型的但是沒有多大幫助的定義(或者可以說是描述)

  可以從多個編程線程中調用無需線程之間不必要的交互

  可以同時被多個線程調用不需要調用一方有任何操作

  有這樣的定義就不奇怪我們對於線程安全性會感到如此迷惑這些定義比說一個類在可以被多個線程安全調用時就是線程安全的好不了多少當然它的意義就是如此但是它不能幫助我們區分一個線程安全的類與一個線程不安全的類安全的意義是什麼呢?

  實際上所有線程安全的定義都有某種程序的循環因為它必須符合類的規格說明 這是對類的功能其副作用哪些狀態是有效和無效的不可變量前置條件後置條件等等的一種非正式的松散描述(由規格說明給出的對象狀態約束只應用於外部可見的狀態即那些可以通過調用其公共方法和訪問其公共字段看到的狀態而不應用於其私有字段中表示的內部狀態)

  線程安全性

  類要成為線程安全的首先必須在單線程環境中有正確的行為如果一個類實現正確(這是說它符合規格說明的另一種方式)那麼沒有一種對這個類的對象的操作序列(讀或者寫公共字段以及調用公共方法)可以讓對象處於無效狀態觀察到對象處於無效狀態或者違反類的任何不可變量前置條件或者後置條件的情況

  此外一個類要成為線程安全的在被多個線程訪問時不管運行時環境執行這些線程有什麼樣的時序安排或者交錯它必須仍然有如上所述的正確行為並且在調用的代碼中沒有任何額外的同步其效果就是在所有線程看來對於線程安全對象的操作是以固定的全局一致的順序發生的

  正確性與線程安全性之間的關系非常類似於在描述 ACID(原子性一致性獨立性和持久性)事務時使用的一致性與獨立性之間的關系從特定線程的角度看由不同線程所執行的對象操作是先後(雖然順序不定)而不是並行執行的

  方法之問的狀態依賴

  考慮下面的代碼片段它迭代一個 Vector 中的元素盡管 Vector 的所有方法都是同步的但是在多線程的環境中不做額外的同步就使用這段代碼仍然是不安全的因為如果另一個線程恰好在錯誤的時間裡刪除了一個元素則 get() 會拋出一個 ArrayIndexOutOfBoundsException

   Vector v = new Vector();
     // contains race conditions may require external synchronization
     for (int i=; i<vsize(); i++) {
       doSomething(vget(i));
     }

  這裡發生的事情是 get(index) 的規格說明裡有一條前置條件要求 index 必須是非負的並且小於 size() 但是在多線程環境中沒有辦法可以知道上一次查到的 size() 值是否仍然有效因而不能確定 i

  更明確地說這一問題是由 get() 的前置條件是以 size() 的結果來定義的這一事實所帶來的只要看到這種必須使用一種方法的結果作為另一種講法的輸入條件的樣式它就是一個 狀態依賴就必須保證至少在調用這兩種方法期間元素的狀態沒有改變一般來說做到這一點的唯一方法在調用第一個方法之前是獨占性地鎖定對象一直到調用了後一種方法以後在上面的迭代 Vector 元素的例子中您需要在迭代過程中同步 Vector 對象

  線程安全程度

  如上面的例子所示線程安全性不是一個非真即假的命題 Vector 的方法都是同步的並且 Vector 明確地設計為在多線程環境中工作但是它的線程安全性是有限制的即在某些方法之間有狀態依賴(類似地如果在迭代過程中 Vector 被其他線程修改那麼由 Vectoriterator() 返回的 iterator 會拋出 ConcurrentModificationException )

  對於 Java 類中常見的線程安全性級別沒有一種分類系統可被廣泛接受不過重要的是在編寫類時盡量記錄下它們的線程安全行為

  Bloch 給出了描述五類線程安全性的分類方法不可變線程安全有條件線程安全線程兼容和線程對立只要明確地記錄下線程安全特性那麼您是否使用這種系統都沒關系這種系統有其局限性 各類之間的界線不是百分之百地明確而且有些情況它沒照顧到 但是這套系統是一個很好的起點這種分類系統的核心是調用者是否可以或者必須用外部同步包圍操作(或者一系列操作)下面幾節分別描述了線程安全性的這五種類別

  不可變

  本欄目的普通讀者聽到我贊美不可變性的優點時不會感到意外不可變的對象一定是線程安全的並且永遠也不需要額外的同步因為一個不可變的對象只要構建正確其外部可見狀態永遠也不會改變永遠也不會看到它處於不一致的狀態Java 類庫中大多數基本數值類如 Integer String 和 BigInteger 都是不可變的

[]  []  


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27774.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.