单例模式-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 }