
确保一个类只有一个实例,并提供全局访问点。私有化构造器,静态方法和静态变量
管理共享资源:线程池、缓存、偏好设置
全局变量和单例模式 :急切实例化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;
}
}