饿汉式:
public class Singleton{
public static final Singleton INSTANCE = new Singleton();
// 注意将默认的无参构造方法访问权限符置为private,防止外部调用该构造方法会new出更多对象实例
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
单例实现缺点:
- 如果构造方法存在过多的处理,会导致加载这个类很慢,可能会引起性能问题
- 在未调用getInstance方法时,JVM也会在加载Singleton类时候去实例化静态字段的INSTANCE,造成内存资源的浪费
懒汉式:
public class Singleton{
public static Singleton INSTANCE;
// 注意将默认的无参构造方法访问权限符置为private,防止外部调用该构造方法会new出更多对象实例
private Singleton(){}
/**
多线程情况下,会出现生成多个实例对象问题,导致单例失效
**/
public static Singleton getInstance_1(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
/**
加上synchronized实现线程同步,可解决多线程情况下单例失效问题,但是考虑到getInstance()方法是一个被频繁调用的方法,这时候会出现性能下降问题,一般不推荐使用这种实现单例的方式
*/
public static synchronized Singleton getInstance_2(){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
双重检查加锁模式(DCL model)
ublic class Singleton{
public static volatile Singleton INSTANCE;
// 注意将默认的无参构造方法访问权限符置为private,防止外部调用该构造方法会new出更多对象实例
private Singleton(){}
public static Singleton getInstance(){
if(INSTANCE == null){
synchronized(Singleton.class){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
volatile是一个轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性
利用static机制:
在Java中,类的静态初始化会在类被加载时出发(此过程在JVM内部已加锁,保证线程同步,因此多线程情况下单例不会失效)
ublic class Singleton{
// 注意将默认的无参构造方法访问权限符置为private,防止外部调用该构造方法会new出更多对象实例
private Singleton(){}
public static Singleton getInstance(){
return SingletonInstanceHolder.INSTANCE;
}
public static class SingletonInstanceHolder{
private static Singleton INSTANCE = new Singleton();
}
}
需要思考一下:单例模式真的能保证只生成一个实例对象吗?
其实要打破实例对象的唯一性,也是有方法来实现的:
- 使用反射,反射可以无视构造器的私有属性
- 如果单例类实现了Cloneable接口,还是可以拷贝出许多个实例的
- Java的Serializable也可以创建出多个实例来的
- 使用多个类加载器(ClassLoader)来加载单例类,也可以创建出多个实例来的
网友评论