单例模式-Singleton

单例(Singleton)是一种常用的设计模式。在Java应用中,单例模式能保证在一个JVM中,该对象只有一个实例对象存在。这样的模式有几个好处:

1. 有些大型类的对象创建比较复杂,系统开销大,可以考虑使用单例模式。

2. 省去了new操作符,降低了系统内存的使用频率,减轻GC压力。

3. 有些类控制着整个业务流程,如果可以创建多个对象的话,系统就乱了。只有使用单例模式,才能保证核心引擎独立控制整个流程。

 

先写一个饿汉式的单例模式:这种模式的好处就是不会产生线程安全问题

1 private class Singleton {           
2     private static Singleton instance = new Singleton(); 
3     
4     private Singleton() {}
5 
6     public static Singleton getInstance() {
7         return instance;           
8     }
9 }

通过这个简单的代码,可以看出单例模式有以下特性:

1. 构造函数私有化:防止对象在外部被创建

2. 公有的获取实例的函数getInstance():可以从外部通过Singleton.getInstance()获取实例

3. 私有且静态的Singleton类型成员变量

本人认为饿汉式单例模式已经够用了,因为使用单例模式就为了使用它的实例对象,在类加载时创建和在使用时创建没有很大区别

 

下面介绍一下懒汉式单例模式:可能会有线程安全性问题

 1 public class Singleton {  
 2   
 3     private static Singleton instance = null;  
 4   
 5     private Singleton() {}  
 6 
 7     public static Singleton getInstance() {  
 8         if (instance == null) {  
 9             instance = new Singleton();  
10         }
11         return instance;  
12     }
13 }

为解决线程安全问题,可以对方法加上synchronized,得到下面的单例模式:

 1 public class Singleton {  
 2   
 3     private static Singleton instance = null;  
 4   
 5     private Singleton() {}  
 6 
 7     public static synchronized Singleton getInstance() {  
 8         if (instance == null) {  
 9             instance = new Singleton();  
10         }
11         return instance;  
12     }
13 }

此方式类似于:

 1 public class Singleton {  
 2   
 3     private static Singleton instance = null;  
 4   
 5     private Singleton() {}  
 6 
 7     public static Singleton getInstance() {  
 8         synchronized(instance) {
 9             if (instance == null) {  
10                 instance = new Singleton();  
11             }
12         }
13         return instance;  
14     }
15 }

但是,此方法由于每次调用getInstance()时都会访问一次锁(为对象加锁),但是实际的情况是只有第一次调用时才应该加锁,因此效率低下,可以使用两次判断(double check)方式提高锁效率:

 1 public class Singleton {  
 2   
 3     private static Singleton instance = null;  
 4   
 5     private Singleton() {}  
 6 
 7     public static Singleton getInstance() {  
 8         if(instance == null) {
 9             synchronized(instance) {
10                 if (instance == null) {  
11                     instance = new Singleton();  
12                 }
13             }
14         }
15         return instance;  
16     }
17 }

此方法类似于:

 1 public class Singleton {  
 2   
 3     private static Singleton instance = null;  
 4   
 5     private Singleton() {}  
 6 
 7     public static Singleton getInstance() {  
 8         if (instance == null) {
 9             buildInstance();
10         }
11         return instance;  
12     }
13 
14     private static synchronized void buildInstance() {
15         if (instance == null) {  
16             instance = new Singleton();  
17         }
18     }
19 }

 

由于JVM内部的类加载机制能够保证当一个类被加载的时候,加载过程是线程互斥的。这样,我们可以使用内部类来维护单例的实现:当我们第一次调用getInstance()的时候,JVM能够帮我们保证instance只被创建一次,这样我们就不用担心线程安全问题。同时该方法只会在第一次调用的时候使用互斥机制,这样又解决了效率低的问题。这样我们可以得到下面的单例模式:

 1 public class Singleton {  
 2   
 3     private Singleton() { } 
 4  
 5     private static class SingletonFactory {  
 6         private static Singleton instance = new Singleton();  
 7     } 
 8   
 9     public static Singleton getInstance() {  
10         return SingletonFactory.instance;  
11     } 
12 }

 

追加:只有一个元素的枚举即是单例

1 public enum Singleton {
2     SINGLETON
3 }

 

posted on 2016-11-03 11:53  Joshua_AW  阅读(300)  评论(0编辑  收藏  举报

导航