单例模式(Singleton Pattern):用来建立独一无二的,只能有一个实例的对象的入场券。html
在咱们进行开发的时候,有些对象咱们只须要一个,好比:配置文件,工具类,线程池、缓存、日志对象等。若是创造出多个实例,就会致使许多问题,好比占用资源过多,不一致的结果等。使用单例模式就能保证在程序中须要的实例只有一个。编程
单例模式的类型:懒汉模式、饿汉模式。缓存
下面是单例模式的类图:安全
咱们将建立一个单例对象类 - Singleton。单例对象(Singleton)类的构造函数是私有的,而且具备自身的静态实例。多线程
Singleton类提供了一个静态方法来获取其静态实例到外部世界。SingletonTest或示例类将使用Singleton类提供的静态方法来获取Singleton对象。yii
饿汉式是在建立自身的静态实例的时候就直接实例化单例对象,而后在提供的静态方法中直接返回这个实例对象。函数
1 /** 2 * 单例模式(饿汉模式) 3 * @author admin 4 * 5 */ 6 public class Singleton { 7 //1.将构造方法私有化,不容许外部直接建立对象 8 private Singleton(){ 9 } 10 11 //2.建立类的惟一实例,使用private,static修饰 12 private static Singleton instance = new Singleton(); 13 14 //3.提供一个用于获取实例的方法,使用public static 修饰 15 public static Singleton getInstance(){ 16 return instance; 17 } 18 }
懒汉式在建立自身的静态实例的时候不直接实例化单例对象,只有在外部调用获取单例对象的静态方法的时候才会判断单例对象是否已经存在,若是 不存在则建立一个并返回,若是已经存在则直接返回。工具
1 /** 2 * 单例模式(懒汉模式) 3 * @author admin 4 */ 5 public class Singleton2 { 6 //1.将构造方法私有化,不容许外边直接建立对象 7 private Singleton2(){ 8 } 9 //2.声明类的惟一实例,使用private,static修饰,可是此处不实例化 10 private static Singleton2 instance; 11 //3.提供一个用于获取实例的方法,使用public static修饰 12 public static Singleton2 getInstance(){ 13 if (instance == null) { 14 instance = new Singleton2(); 15 } 16 return instance; 17 } 18 }
1 /** 2 * 单例模式的测试类 3 * @author admin 4 * 5 */ 6 public class SingletonTest { 7 public static void main(String[] args) { 8 //饿汉模式 9 Singleton s1 = Singleton.getInstance(); 10 Singleton s2 = Singleton.getInstance(); 11 12 if (s1 == s2) { 13 System.out.println("s1和s2是同一个对象"); 14 }else { 15 System.out.println("s1和s2不是同一个对象"); 16 } 17 18 //懒汉模式 19 Singleton2 s3 = Singleton2.getInstance(); 20 Singleton2 s4 = Singleton2.getInstance(); 21 if (s3 == s4) { 22 System.out.println("s3和s4是同一个对象"); 23 }else { 24 System.out.println("s3和s4不是同一个对象"); 25 } 26 } 27 }
测试结果:性能
从测试结果能够看出来,获取的对象是同一个对象,也就是说,返回的是单例对象。测试
上面的代码在普通的应用程序中没有任何任何问题,可是在多线程中使用的时候就会发现,返回的单例对象并非惟一的,并且多个不一样的单例对象,这就说明在多线程中,单例模式产生的单例对象并非"惟一"的。要解决这个问题,有3种办法(其中两种方法都是针对懒汉式的),这3种方法在解决多线程问题的同时也有本身的缺点:
1 /** 2 * 单例模式(懒汉模式) 3 * @author admin 4 */ 5 public class Singleton2 { 6 //1.将构造方法私有化,不容许外边直接建立对象 7 private Singleton2(){ 8 9 } 10 //2.声明类的惟一实例,使用private,static修饰,可是此处不实例化 11 private volatile static Singleton2 instance; 12 //3.提供一个用于获取实例的方法,使用public static修饰 13 public static Singleton2 getInstance(){//检查实例,若是不存在就进入同步区块 14 if (instance == null) { 15 synchronized (Singleton2.class){//注意,只有第一次才完全执行这里的代码 16 if (instance == null) {//进入区块后,再检查一次,若是仍是null,才建立实例 17 instance = new Singleton2(); 18 } 19 } 20 } 21 return instance; 22 } 23 }
volatile关键字确保:当单例变量被初始化成Singleton实例时,多个线程正确地处理单例变量。若是性能问题是关注的重点,那么这个方法能够大大地减小getInstance()的时间消耗。可是该方法也有其缺点,那就是双重检查加锁不适用于1.4及更早版本的Java。在1.4及其更早的版本中,许多JVM对于volatile关键字的实现会致使双重检查加锁的实效。若是不能使用Java5以上的版本,而必须使用旧版本,那么该方法就没法解决多线程的问题。
好了单例模式的叙述到此就结束了,若是有什么讲解的不正确的地方,欢迎你们多多指教!
文章部份内容引用自以下地址:http://www.yiibai.com/design_pattern/singleton_pattern.html