Android 設計模式—單例模式記要

單例模式

定義:(定義都是抽象的,無需過度在意其意義,設計模式這種東西只可意會不可言傳)確保一個類只有一個實例,而且自行實例化并向整個系統提供這個實例。

單例模式寫法有很多種,因地制宜就行,但關鍵點都是在并發問題上:

1.private構造函數

2.public static靜態公有方法

3.保證線程安全,適應多線程并發訪問:(2個關鍵點)

? ? ? ? * 同步鎖synchronized修飾符:避免同時被多個線程訪問,防止線程不同步,保證并發情況下的原子性,可見性,有序性

? ? ? ? ? * Volatile修飾符:本質是在告訴jvm當前變量在寄存器中的值是不確定的,需要從內存中讀取(它修飾的變量的讀寫操作都必須在內存中進行),保證了多線程共享變量的可見性,原子性(需條件),有序性(需條件))。

4.保證訪問性能(例如單例每次訪問都進行synchronized判斷影響性能)

5.相關:因為單例涉及并發,涉及synchronized和Volatile修飾符,這2者都關系到CUP線程與內存交互,java內存模擬。不論是synchronized還是Volatile都是對下面3個保證性問題進行的操作,只是在某些情況下適用或者不適用。

? ? ? ? 5.1.Java內存模擬JMM(JMM定義了java虛擬機JVM在內存中的工作方式)

JMM定義了多線程之間共享變量的可見性,一個線程對共享變量的寫入何時對另一個線程可見,以及如何在需要的時候對共享變量進行同步。

? ? ? ? 5.2.并發編程必須的3個保證性問題:原子性問題,可見性問題,有序性問題

? ? ? ? ? *原子性:一個操作,要么全部執行并且執行的過程不會被任何因素打斷,要么就不執行。

理解場景:A向B轉賬500元操作;2個步驟,賬戶A減去500元,賬戶B加上500元:A減500èB加500;過程中如果插入個賬戶B取走500元:A減500èB減500èB加500。原本是2步,變為3步。轉賬結果就會發生錯誤。

只有簡單的讀取,儲存操作才是原子操作如I= 10(變量之間的互相賦值不是原子操作),如果要實現更大范圍操作的原子性,可以通過synchronized,因為鎖能保證一個時刻只有一個線程執行代碼塊,從而不存在原子性問題。

? ? ? ? *可見性:當多個線程訪問同一個變量,一個線程修改了變量的值,他線程能立即看到修改的值。

理解場景:CPU1下線程1執行int I = 0 , I = 10,CPU2下線程2執行 j = I ;假若線程1初始化? I = 0 后將 I = 10放入高速緩存中,但是沒有放入主存中,此時線程2執行,從主存中讀取的仍然是? ? ? I = 0 ,j 就不等于10。線程1已經改變了i的值,但是線程2沒有立即看到線程1修改的值,導致可見性問題。

Synchronized的鎖能保證同一時間只有一個線程執行代碼塊的同時,在釋放鎖之前會將對變量的修改刷新到主存當中,因此避免上面場景中的問題,進而解決可見性問題。

? ? ? ? *有序性:程序執行的順序按照代碼的先后順序執行。

注意場景:指令重排序(InstructionReorder):處理器為了提高程序運行效率,可能會對輸入的代碼進行優化,不保證各個語句的執行先后順序同代碼順序一致,但是保證執行結果一致(單線程一致,多線程233)。

Synchronized的鎖能保證同一時間只有一個線程執行代碼塊,相當于單線程執行,自然保證有序性。

Volatile禁止進行指令重排序。

? ? ? ? ? 5.3.使用volatile必須具備以下2個條件:(2個條件就是保證操作是原子性操作,從而保證使用volatile關鍵字的程序在并發時能夠正確執行。)

*對變量的寫操作不依賴于當前值

*該變量沒有包含在具有其他變量的不變式中

? ? ? ? ? 5.4.synchronized關鍵字是防止多個線程同時執行一段代碼,那么就會很影響程序執行效率,而volatile關鍵字在某些情況下性能要優于synchronized,但是要注意volatile關鍵字是無法替代synchronized關鍵字的,因為volatile關鍵字無法保證操作的原子性。

下周不是線程就是工廠模式。。


對于生活理想,應該像宗教徒對待宗教一樣充滿虔誠與熱情!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容