设计模式之单例模式
介绍
单例模式即在整个系统应用中存在唯一的对象实例。通过将构造函数私有化,且基本上只提供唯一的静态方法来进行访问。
属于创建型模式。
七种方式
单例模式大致分为懒汉式,饿汉式,内部类,枚举这几种,再根据线程是否安全细分为7种。
下面将详细列举出这7种:
1.静态常量饿汉式(线程安全)
public class Singleton {
//构造方法私有
private Singleton(){}
//创建对象实例
private final static Singleton singleton=new Singleton();
//获得对象
public Singleton getSingleton(){
return singleton;
}
}
此种方式的优点就是简单,并且在类加载的时候就创建了对象,避免了线程安全导致的问题。缺点就是一旦某种原因进行了类加载就会创建对象,假如说系统不会用到此对象,就会造成内存浪费。
2.静态代码块饿汉式(线程安全)
public class Singleton {
//构造方法私有
private Singleton(){}
//声明对象
private static Singleton singleton;
//静态代码块
static {
singleton=new Singleton();
}
//获得对象
public Singleton getSingleton(){
return singleton;
}
}
此种方式的优缺点与上面的静态常量方式几乎相同,都是在类加载的时候进行实例化(类加载的时侯会对静态变量和静态代码块进行初始化)
3.线程不安全懒汉式
public class Singleton {
//构造方法私有
private Singleton(){}
//声明对象
private static Singleton singleton;
//获得对象
public Singleton getSingleton(){
if (singleton==null)
singleton=new Singleton();
return singleton;
}
}
此方式优点就是实现了懒加载,只有在用到的时候进行对象的实例化,避免了内存浪费。
缺点是线程不安全,假如说在执行到if(singleton==null)这句代码,第一个线程执行了这句代码判断为true后还未来得及往下执行,第二个线程也执行了这段代码,这样就会new两次创建两个对象。
4.线程安全懒汉式
public class Singleton {
//构造方法私有
private Singleton(){}
//声明对象
private static Singleton singleton;
//获得对象
public synchronized Singleton getSingleton(){
if (singleton==null)
singleton=new Singleton();
return singleton;
}
}
在线程不安全懒汉式方式的基础上,往获得对象的方法上加synchronized修饰符,这样保证了线程安全,但是效率太低了,每次获得对象都要进行加锁操作,在实际开发中几乎不使用这种方法。
5.DoubleCheck(重要)
public class Singleton {
//构造方法私有
private Singleton(){}
//声明对象
private static volatile Singleton singleton;
//获得对象
public Singleton getSingleton(){
if (singleton==null)
synchronized (Singleton.class){
if (singleton==null)
singleton=new Singleton();
}
return singleton;
}
}
双重检查方式,即保证了效率,又实现了懒加载,还保证了线程安全,是非常推荐的一种方式,也是面试常考的方式。
大家可能有点奇怪,这里怎么用了两个判空操作?我不是都加synchronized了?为什么用volatile修饰singleton?
这个地方其实很奇妙,还是按照上次的例子:假如我这里没有第二个判空操作,当第一个线程执行了第一个判空操作后进入下面代码还未执行,第二个线程也进来判空,就无法保证线程安全。当有第二个判空操作时,先进来的线程进入同步代码块实例化了对象,而由于同步代码块的存在,后来的线程先在外面等着,等第一个线程执行完后再进入,此时它再判空后就得到了false,不再实例化对象。保证了线程安全。volatile在这里的作用是防止指令重排,保证代码正常的执行顺序。
6.静态内部类(线程安全)
public class Singleton {
//构造方法私有
private Singleton(){}
//声明内部类
private static class SingletonInstance{
private final static Singleton singleton=new Singleton();
}
//获得对象
public Singleton getSingleton(){
return SingletonInstance.singleton;
}
}
内部类的一个特点:当外部类进行类加载时,内部类并不会被加载。
当只有调getSingleton()方法时SingletonInstance才会类加载。所以静态内部类方式可以实现懒加载,且加载的时候是线程安全的,且类加载只一次,这样就实现了线程安全和单例。
7.枚举(线程安全)
enum Singleton {
SINGLETON
}
JDK1.5加入的枚举,让代码简单到让人不可思议!
枚举可以解决上述所有问题,还能防止反射创建对象,太强大了!

浙公网安备 33010602011771号