设计模式--单例模式
确保一个类只有一个实例,并提供全局访问点。私有化构造器,静态方法和静态变量
管理共享资源:线程池、缓存、偏好设置
全局变量和单例模式 :急切实例化VS延迟实例化
1.懒汉式
public class Singleton { private static Singleton instance = null; private Singleton(){ } public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
线程安全版本:
1.使用同步方法(synchronized关键字),性能差
public class Singleton { private static Singleton instance = null; private Singleton(){ } public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
2.使用饿汉式(急切实例化,JVM加载时,就会创建唯一的实例)
public class Singleton { //私有化成员变量 private static Singleton instance = new Singleton(); //私有化构造器 private Singleton(){ } //只提供public的getter方法,但是没有setter方法 public static Singleton getInstance(){ return instance; } }
3.用“双重检查加锁”,来减少使用同步
public class Singleton{ private volatile static Singleton instance = null; private Singleton(){ } public static Singleton getInstance(){ if(instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
在懒汉式的线程安全版本中,也可能存在问题
* 在Java指令中创建对象和赋值操作是分开进行的,
* 也就是说instance = new Singleton();语句是分两步执行的。
* 但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,
* 然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,
* 我们以A、B两个线程为例:
a>A、B线程同时进入了第一个if判断
b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();
c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,
并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。
d>B进入synchronized块,由于instance此时不是null,
因此它马上离开了synchronized块并将结果返回给调用该方法的程序。
e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。
* 采用静态内部类的方法来创建
* 单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,
* 这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,
* JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,
* 这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,
* 这样就解决了低性能问题
public class Singletone3 { /*私有化构造器*/ private Singletone3(){ } /*使用内部类来维护单例模式*/ private static class SingletoneFactory{ private static Singletone3 instance = new Singletone3(); } /*获取实例*/ public static Singletone3 getInstance(){ return SingletoneFactory.instance; } }