差異處

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

連向這個比對檢視

Both sides previous revision 前次修改
下次修改
前次修改
java:effective_java:concurrency:use_lazy_initialization_judiciously [2020/02/02 13:01]
tony
java:effective_java:concurrency:use_lazy_initialization_judiciously [2023/06/25 09:48] (目前版本)
行 25: 行 25:
  public static Singleton get() {  public static Singleton get() {
  Singleton result = instance;  Singleton result = instance;
- if( instance ​== null ) {+ if( result ​== null ) {
  result = instance = new Singleton();​  result = instance = new Singleton();​
  }  }
行 47: 行 47:
 </​code>​ </​code>​
 這做法的缺點就是在初始化之後,每一個Thread要存取時,都會受到這個synchronized的影響而慢一點。 這做法的缺點就是在初始化之後,每一個Thread要存取時,都會受到這個synchronized的影響而慢一點。
-=====Double-check idiom =====+===== Double-check idiom =====
 雙重檢查鎖定模式的做法,能解決使用Synchronized Method效能的問題,又能確保只會初始化一次:​ 雙重檢查鎖定模式的做法,能解決使用Synchronized Method效能的問題,又能確保只會初始化一次:​
 <code java> <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) { 
 + result = instance; 
 + if( result != null ) { // with locking 
 + return result; 
 +
 +  
 + result = instance = new Singleton();​ 
 +  
 +
 + return result; 
 +
 +}
 </​code>​ </​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作者力推的方法,在Item89有提及。在這我就稍微說明Enum method的做法:​
 +<code java>
 +public enum Singleton {
 +
 + INSTANCE;
 +
 + public static Singleton get() {
 + return INSTANCE;
 + }
 +}
 +</​code>​
 +Enum擁有Thread-safe、只能被初始化一次且不能夠被繼承的特性;缺點就是無法做Lazy initialization,要解決這問題可以與Holder方式結合。但與其這樣,不如使用Holder就好。
 +
 +
 ===== Note ===== ===== Note =====
 Effective Java第三版Item 83。 Effective Java第三版Item 83。
 ===== Reference ===== ===== Reference =====
   * Java Threads, 3/e   * Java Threads, 3/e
 +  * Effective Java, 3/e
   * Java高併發編程詳解:多線程與架構設計,​ 汪文君   * 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|雙重檢查鎖定模式]]   * [[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|雙重檢查鎖定模式]]