浅析Java设计模式 - 单例模式

Posted Djokovic

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅析Java设计模式 - 单例模式相关的知识,希望对你有一定的参考价值。

以下是三种单例模式的代码实现,前两者用的比较多 (言外之意 最后一种可以忽略)

技术分享
  1 package com.signle;
  2 
  3 import java.util.HashMap;
  4 import java.util.Map;
  5 
  6 /**
  7  * 
  8  * @title 单例模式  
  9  * @Copyright Copyright (c)2016年3月9日
 10  * @Company CTC
 11  * @version 1.0
 12  * @author ejokovic
 13  * @time   上午11:21:53
 14  * @package
 15  * com.signle
 16  *
 17  */
 18 public class TestSignle {
 19     public static void main(String[] args) {
 20         Singleton s = Singleton.getInstance();
 21         Singleton s1 = Singleton.getInstance();
 22         //System.out.println(s==s1);
 23         SigletionC singleC = SigletionC.getInstance(null);  
 24         System.out.println(singleC.about()); 
 25     }
 26     
 27 }
 28 
 29 /**
 30  * 懒汉式
 31  *  是线程不安全的并发环境下很可能出现多个Singleton实例,要实现线程安全
 32  * @title  
 33  * @Copyright Copyright (c)2016年3月9日
 34  * @Company CTC
 35  * @version 1.0
 36  * @author ejokovic
 37  * @time   上午11:23:44
 38  * @package
 39  * com.signle
 40  *
 41  */
 42 class Singleton{
 43     private Singleton(){}
 44     private static Singleton Singleton;
 45     public static Singleton getInstance(){
 46         if(Singleton==null){
 47             Singleton = new Singleton();
 48         }
 49         return Singleton;
 50     }
 51 }
 52 
 53 /**
 54  * 解决懒汉式单例线程安全(一)
 55  * 在getInstance方法上加同步锁
 56  * @title  
 57  * @Copyright Copyright (c)2016年3月9日
 58  * @Company CTC
 59  * @version 1.0
 60  * @author ejokovic
 61  * @time   上午11:31:45
 62  * @package
 63  * com.signle
 64  *
 65  */
 66 class Singleton2{
 67     private Singleton2(){}
 68     private static Singleton2 Singleton;
 69     public static synchronized  Singleton2 getInstance(){
 70         if(Singleton==null){
 71             Singleton = new Singleton2();
 72         }
 73         return Singleton;
 74     }
 75 }
 76 
 77 /**
 78  * 解决懒汉式单例线程安全(二)
 79  * 双重检查锁定
 80  * @title  
 81  * @Copyright Copyright (c)2016年3月9日
 82  * @Company CTC
 83  * @version 1.0
 84  * @author ejokovic
 85  * @time   上午11:34:42
 86  * @package
 87  * com.signle
 88  *
 89  */
 90 class Singleton3{
 91     private Singleton3(){}
 92     private static Singleton3 Singleton;
 93     public static synchronized  Singleton3 getInstance(){
 94         if(Singleton==null){
 95             synchronized (Singleton3.class){
 96                 if(Singleton==null){
 97                     Singleton = new Singleton3();
 98                 }
 99             }
100         }
101         return Singleton;
102     }
103 }
104 
105 /**
106  * 解决懒汉式单例线程安全(二)
107  * 静态内部类
108  * 这种比上面1、2都好一些,既实现了线程安全,又避免了同步带来的性能影响。
109  * @title  
110  * @Copyright Copyright (c)2016年3月9日
111  * @Company CTC
112  * @version 1.0
113  * @author ejokovic
114  * @time   下午12:06:54
115  * @package
116  * com.signle
117  *
118  */
119 class Singleton4{
120     private static class LazyHolder{
121          private static final Singleton4 INSTANCE = new Singleton4();  
122     }
123     private Singleton4(){}
124     public static synchronized  Singleton4 getInstance(){
125         return LazyHolder.INSTANCE;
126     }
127 }
128 
129 /**
130  * 饿汉式单例类.在类初始化时,已经自行实例化
131  * @title  
132  * @Copyright Copyright (c)2016年3月9日
133  * @Company CTC
134  * @version 1.0
135  * @author ejokovic
136  * @time   下午12:12:23
137  * @package
138  * com.signle
139  *
140  */
141 class SigletionA{
142     private SigletionA(){}
143     private static final SigletionA sigletionA = new SigletionA();
144     public static SigletionA getInstance(){
145         return sigletionA;
146     }
147 }
148 
149 //登记式单例
150 class SigletionC{
151     private static Map<String,SigletionC> map = new HashMap<String,SigletionC>();  
152     static{  
153         SigletionC single = new SigletionC();  
154         map.put(single.getClass().getName(), single);  
155     }  
156     //保护的默认构造子  
157     protected SigletionC(){}  
158     //静态工厂方法,返还此类惟一的实例  
159     public static SigletionC getInstance(String name) {  
160         if(name == null) {  
161             name = SigletionC.class.getName();  
162             System.out.println("name == null"+"--->name="+name);  
163         }  
164         if(map.get(name) == null) {  
165             try {  
166                 map.put(name, (SigletionC) Class.forName(name).newInstance());  
167             } catch (InstantiationException e) {  
168                 e.printStackTrace();  
169             } catch (IllegalAccessException e) {  
170                 e.printStackTrace();  
171             } catch (ClassNotFoundException e) {  
172                 e.printStackTrace();  
173             }  
174         }  
175         return map.get(name);  
176     }  
177     //一个示意性的商业方法  
178     public String about() {      
179         return "Hello, I am RegSingleton.";      
180     }      
181 }
单例模式

 

在了解饿汉与懒汉的区别前 先了解下什么是线程安全:

假如你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时执行这段代码,如果每次执行的结果和单线程中执行的结果一致 且 其它变量的值也和预期的一致 这就是线程安全

换句话说:

一个类或者程序提供的接口对于线程来说是原子操作,或者多个线程之间切换不会导致该接口的执行结果存在差异性 也就是说我们不用考虑同步的问题 那就是线程安全的

 

饿汉式和懒汉式区别:

从名字上来说,饿汉和懒汉:

  饿汉是当类加载时就把单例初始化完成,保证getInstance的时候,单例是已经存在的了

  而懒汉比较懒,只有当调用getInstance的时候,才会去初始化这个单例;

从线程是否安全角度讲:

  饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题

 

  懒汉式本身是非线程安全的,为了实现线程安全有几种写法,分别是上面的1、2、3,这三种实现在资源加载和性能方面有些区别;

从资源加载和性能的角度讲:

    饿汉式在类加载的同时就实例化一个静态对象出来,不管之后是否用到这个静态对象,都会占据一定的内存,但是相应的 在第一次调用时的速度也会更快,因为资源已经初始化好了;

    至于以上1,2,3 这三种实现又有些区别

    第一种,在方法调用上加了同步,虽然线程安全了,但每次都要同步,会影响性能,毕竟大部分的情况下是不需要同步的

    第二种,在getInstance方法中做了两次null检查,确保了只有第一次调用该静态对象的时候才会同步,这样也是线程安全的,同时避免了每次调用时的同步损耗;

    第三种,利用了classloader机制,保证初始化instance时只有一个线程 所以是线程安全的 同时没有性能损耗

以上是关于浅析Java设计模式 - 单例模式的主要内容,如果未能解决你的问题,请参考以下文章

浅析设计模式——创建型模式之Singleton(单例模式)

单例模式浅析

C#浅析单例模式

DCL单例模式浅析

设计模式之单例模式

单例模式与线程安全问题浅析