国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

java 并發編程實戰 之 對象的共享

2019-11-06 07:56:35
字體:
來源:轉載
供稿:網友

對象的共享

可見性

有點類似于數據庫事務中的臟讀,不可重復讀問題,不同的事務就相當于不同的線程,如果沒有設置事務的隔離級別,即線程之間沒有使用同步機制,這時候 A事務 對數據庫的 修改操作由于事務沒有提交,所以B事務是看不到A事務修改后的數據的,即發生了臟讀。類似的在多線程沒有使用同步的情況下,A線程對變量修改,B線程讀取變量,在沒有同步的情況下,AB的執行順序是不能保證的。示例代碼如下,輸出結果可能為0或者沒有輸出。

package net.jcip.examples;/** * NoVisibility * <p/> * Sharing variables without synchronization * * @author Brian Goetz and Tim Peierls */public class NoVisibility { PRivate static boolean ready; private static int number; private static class ReaderThread extends Thread { public void run() { while (!ready) Thread.yield(); System.out.println(number); } } public static void main(String[] args) { new ReaderThread().start(); number = 42; ready = true; }}

在沒有同步的情況下,編譯器、處理器以及運行時等都可能對操作的執行順序,進行一些意想不到的調整,在缺乏足夠同步的多線程中,想要對內存操作的執行順序進行判斷,幾乎無法得出正確的結論。

失效的數據

NoVisibility中當讀線程查看ready變量時,可能會得到一個已經失效的值。

非原子的64位操作

對于 非volatile類型的64位數值變量,JVM允許將64位的讀操作或寫操作分解為兩個32位操作,當讀取一個非volatile類型的long變量時,如果對該變量的讀操作和寫操作在不同的線程中執行,那么很可能會讀取到某個值的高32位和另一個值的低32位的組合結果。這樣就不僅僅是內存可見性問題了。

加鎖與可見性

加鎖的含義不僅僅局限于線程間的互斥行為,還包括內存可見性。

volatile變量

當把變量聲明為volatile變量之后,編譯與運行時,JVM都會注意到這個變量時共享的,時內存可見的,在該變量上的操作,不會與其他的內存操作一起重排序,volatile不會被緩存在寄存器或者其他處理器不可見的地方,因此讀取volatile變量時,總會返回最新寫入的值。 volatile 只保證了內存的可見性,不保證線程之間的的互斥性

發布與逸出

發布一個對象的意思是,是對象能夠在他的作用域之外的代碼中被使用,逸出只的是不該發布的對象被發布出去。

發布一個對象public static Set<Secret> knowSecrets;public void initialize(){ knownSecrets = new HashSet<Secret>();}逸出對象package net.jcip.examples;/** * UnsafeStates * <p/> * Allowing internal mutable state to escape * * @author Brian Goetz and Tim Peierls */class UnsafeStates { private String[] states = new String[]{ "AK", "AL" /*...*/ }; public String[] getStates() { return states; }}

在這里大家不要誤解本書作者的意思,在我們的日常開發中pojo類或者我們的domain經常以這種形式出現,但是在這里作者想表達的意思是對于復雜的業務對象來說的,并不是針對pojo對象。業務對象的可變狀態變量的所有操作應該是由這個業務對象自己控制的,而不是把他的私有狀態變量發布出去,這樣會造成很多不確定、不可控的操作,當然在多線程環境中也不是線程安全的。 可控的復雜的業務對象模型(偽代碼)如下。

class ComplexControlStates { private String[] states = new String[]{ "AK", "AL" /*...*/ }; public String[] opration1() { ...一系列復雜的操作 返回 states 的拷貝對象 } public String[] opration2() { ...一系列復雜的操作 返回 states 的拷貝對象 } public String[] opration3() { ...一系列復雜的操作 返回 states 的拷貝對象 }}

this的隱式逸出

ThisEscape發布EventListener的時候,ThisEscape實例本身也會溢出,因為這個內部類的實例中包含了對ThisEscape實例的隱含引用。個人理解如下(純屬個人理解):匿名內部類可以訪問外部類的final域,如果final域為一個指向復雜對象的引用,這時候就相當于將這個復雜對象發布了出去,從而造成逸出 package net.jcip.examples;/** * ThisEscape * <p/> * Implicitly allowing the this reference to escape * * @author Brian Goetz and Tim Peierls */public class ThisEscape { public ThisEscape(EventSource source) { source.registerListener(new EventListener() { public void onEvent(Event e) { doSomething(e); } }); } void doSomething(Event e) { } interface EventSource { void registerListener(EventListener e); } interface EventListener { void onEvent(Event e); } interface Event { }}

書中的解釋

在構造過程中使this引用一處的一個常見錯誤是,在構造函數中啟用一個線程,無論是顯示構建(使用構造函數)還是隱式的構建(使用Thread或Runnable),this引用都會被新創建的線程共享,在對象未完全構造完成之前,新的線程可以看見他。

線程封閉

當訪問可變的共享變量時,通常需要同步,一種避免使用同步的方法就是不共享,即將變量封閉在單個線程中。這種技術叫做線程封閉。 常見的應用是JDBC的Connection對象。數據庫連接池在將一個connection發布給一個線程之后,在connection還池之前不會再將它分配給其他線程。 詳解 見ThreadLocal對象。

Ad-hoc線程封閉

指,維護線程封閉性的職責完全由程序實現來承擔.。 例子: volatile變量上存在一種特殊的線程封閉,如果能保證只有一個線程可以對volatile變量進行寫操作,而其他任意多的變量都只能進行讀操作,這時候就相當于將volatile的寫操作封裝在了線程內,由于volatile變量的內存可見性,可以保證線程安全。

棧封閉

棧封閉是線程封閉的的一種特例。

棧封閉與JVM內存模型相關,當一個線程執行某個方法的時候,JVM會給這個線程單獨開辟一個線程棧空間,里面存儲了這個方法所有局部變量,而且這些變量是被該線程獨享的。

ThreadLocal 類

不要濫用ThreadLocal,列如將所有全局變量都作為ThreadLocal對象,或者作為一種隱藏方法參數的手段。ThreadLocal變量類似于全局變量,它能降低代碼的可重用性,并在類之間引入隱含的耦合性,使用時需格外小心。

舉一個在實際開發中遇到的例子。 之前做過一個struts2spring mvc的任務,代碼中大量使用了,Struts2的ActionContext對象來獲取Request或session對象,并且耦合在service層甚至是dao層。總之重寫的工作量很大,所以通過一個頂層的Filter來將Request對象保存在ThreadLocal中,并模擬了一個ActionContext對象來代替struts2的ActionContext

不變性

不可變對象一定是線程安全的


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 大方县| 宣化县| 四子王旗| 太原市| 定州市| 偏关县| 茂名市| 前郭尔| 新郑市| 托里县| 巧家县| 健康| 鹤岗市| 广东省| 家居| 双城市| 启东市| 吉木乃县| 景宁| 明光市| 随州市| 栾城县| 北碚区| 霍邱县| 丰县| 封开县| 临夏市| 海原县| 保靖县| 滨海县| 石楼县| 贵港市| 宾阳县| 武宣县| 江西省| 九龙城区| 江西省| 临湘市| 神农架林区| 青阳县| 晋江市|