差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

java:effective_java:concurrency:use_lazy_initialization_judiciously [2020/02/02 13:24]
tony
java:effective_java:concurrency:use_lazy_initialization_judiciously [2023/06/25 09:48]
行 1: 行 1:
-{{tag>​java effective_java java_concurrency}} +
-====== Effective Java - Use lazy initialization judiciously ====== +
-===== Problem ===== +
-這個Item是在探討使用Lazy initialization的時機與方法,而在多執行緒存取的時,較容易發生問題。如以下程式要初始化一個Singleton物件,但在多執行緒的情況下,Client可能會拿到不是唯一的instance:​ +
-<code java> +
-public class Singleton { +
-  +
- private static Singleton instance; +
-  +
- public static Singleton get() { +
- if( instance == null ) { +
- instance = new Singleton();​ +
-+
- return instance; +
-+
-+
-</​code>​ +
-===== Single-check idiom ===== +
-第一個方法是基於原本問題的改良,適用於能接受重複初始化,會比問題程式碼效能稍微好一些。 +
-<code java> +
-public class Singleton { +
-  +
- private static volatile Singleton instance; +
-  +
- public static Singleton get() { +
- Singleton result = instance; +
- if( result == null ) { +
- result = instance = new Singleton();​ +
-+
- return result; +
-+
-+
-</​code>​ +
-這裡用result local variable的原因,是為了要讓instance變數在已初始化情況下只存取一次;這是由於volatile宣告會強制Thread在使用instance時,去讀取最新的資料。根據作者所說,效能會差1.4倍。 +
-===== Normal Initialization ===== +
-在一般情況下,因為JVM ClassLoader載入類別是Thread-Safe,直接使用以下方法就不會有Multi-thread的問題:​ +
-<code java> +
-private final static Singleton instance = new Singleton();​ +
-</​code>​ +
-但如果初始化這個物件的效能成本很大,希望能等到有使用到才初始化,就不適用這種做法。 +
-===== Synchronized Method ===== +
-針對要做延遲初始化又要Thread-Safe,我年輕時且目前看到最多人使用的寫法如下:​ +
-<code java> +
-public synchronized static Singleton get() { +
-//... +
-+
-</​code>​ +
-這做法的缺點就是在初始化之後,每一個Thread要存取時,都會受到這個synchronized的影響而慢一點。 +
-===== Double-check idiom ===== +
-雙重檢查鎖定模式的做法,能解決使用Synchronized Method效能的問題,又能確保只會初始化一次:​ +
-<code java> +
-public class Singleton { +
-  +
- private static Singleton instance; +
-  +
- public static Singleton get() { +
- Singleton result = instance; +
- if( result != null ) { // no locking +
- return result; +
-+
-  +
- synchronized(Singleton.class) { +
- if( instance != null ) { // with locking +
- return instance; +
-+
-  +
- result = instance = new Singleton();​ +
-  +
-+
- return result; +
-+
-+
-</​code>​ +
-第一次的instance檢查不會受lock控管,只要在第一次初始化後,就能夠使用;第二次的instance檢查是為了避免Multi-thread情況下,重複初始化的問題。這個方法適用於非static的欄位,我是都以static當例子較簡單。(我的程式碼與effective java有落差,因為我認為書內的程式在with locking的檢查並沒assign instance給result,一定會有問題) +
-===== Lazy initialization holder class idiom ===== +
-Lazy initialization holder class的做法,之前在第二版的時候並沒有特別注意,直到我看Java高併發編程詳解:多線程與架構設計這本書時,才意會到這寫法使用在static欄位初始化會比double-check idiom方式簡單很多。程式碼如下:​ +
-<code java> +
-public final class Singleton { +
- private static class Holder { +
- static final Singleton instance = new Singleton();​ +
-+
-  +
- public static Singleton get() { +
- return Holder.instance;​ +
-+
-+
-</​code>​ +
-這一樣是透過ClassLoader載入Class Thread-Safe的機制,來解決同步存取的問題。目前這是要初始化static欄位的首選。 +
-===== Enum method ===== +
-這方法是看Java高併發編程詳解:多線程與架構設計這本書時,有提到透過Enum去解這問題是Effective Java作者力推的方法,但我在第二版與第三版中並沒看到,可能是第一版的內容。在這我就稍微說明Enum method的做法。 +
-===== Note ===== +
-Effective Java第三版Item 83。 +
-===== Reference ===== +
-  * Java Threads, 3/e +
-  * Java高併發編程詳解:多線程與架構設計,​ 汪文君 +
-  * [[https://​zh.wikipedia.org/​wiki/​%E5%8F%8C%E9%87%8D%E6%A3%80%E6%9F%A5%E9%94%81%E5%AE%9A%E6%A8%A1%E5%BC%8F|雙重檢查鎖定模式]] +
-=====    ===== +
----- +
-\\ +
-~~DISQUS~~+