来源于headfirst设计模式
单例模式的性能指标:lazy(是否延迟实例化),线程安全
一、延迟实例化,同步(synchronized)方法-->由于是单例更需要考虑处理问题需要考虑的同步问题,延迟实例化主要是面向资源敏感的对象
1 public class Singleton { 2 3 private static Singleton uniqueinstance;//唯一的实例变量 4 5 private Singleton() {//私有的初始化方法 6 } 7 8 public static synchronized Singleton getInstance() { 9 //实例的获取方法,将普通的初始化方法变为获得方法 10 if (uniqueinstance== null) { 11 uniqueinstance= new Singleton();//直接在类内部初始化 12 } 13 return instance; 14 } 15 }
二、直接实例化(静态工厂方法)
1 public class Singleton { 2 3 private static Singleton uniqueInstance = new Singleton(); 4 //直接创建单例 5 private Singleton() { 6 } 7 8 public static Singleton getInstance() { 9 10 return uniqueInstance; 11 } 12 }
三、双重检验加锁,双重检查锁定模式首先验证锁定条件(第一次检查),只有通过锁定条件验证才真正的进行加锁逻辑并再次验证条件(第二次检查)。-->用来减少并发系统中竞争和同步的开销。[http://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]
public class Singleton { private volatile static Singleton instance = null;//volatile变量 private Singleton() { } public static Singleton getInstance() { if (instance == null) {//只有首次初始化时才用到了同步模块,避免了同步对资源的浪费 synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
volatile变量的作用[参考:http://blog.csdn.net/orzorz/article/details/4319055]
用在多线程,为了同步变量。在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。
一个变量声明为volatile,就意味着这个变量是随时会被其他线程修改的,因此不能将它cache在线程memory中。synchronized的优势在于其可以把方法或者代码块变为原子操作,而volatile无法。
四、枚举单例,上面的方法都有一个问题就是反序列化,破坏了单例的特性,你可以去查询使用readResolve(),但比较麻烦,推荐使用Java的这个新特性——枚举类型。它具有内置的序列化支持和线程安全支持。
public
enum
EasySingleton{
INSTANCE;
}
在 java 垃圾回收中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。
[http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html]
五、各种优化
/** * 基于内部类的单例模式 Lazy 线程安全 * 优点: * 1、线程安全 * 2、lazy * 缺点: * 1、待发现 * * @author laichendong * @since 2011-12-5 */ public class SingletonFive { /** * 内部类,用于实现lzay机制 */ private static class SingletonHolder{ /** 单例变量 */ private static SingletonFive instance = new SingletonFive(); } /** * 私有化的构造方法,保证外部的类不能通过构造器来实例化。 */ private SingletonFive() { } /** * 获取单例对象实例 * * @return 单例对象 */ public static SingletonFive getInstance() { return SingletonHolder.instance; } }
http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html
这种方式利用静态内部类的优势,既是后实例化的又是线程安全的。