单例模式
2018-01-30 本文已影响3人
HWilliamgo
public class Singleton {
/**
* 饿汉模式
* 在类加载时就完成了静态对象的初始化,所以类加载较慢,但获取对象的速度较快
* 这种方式基于类加载机制,避免了多线程同步问题。
* 但是由于在类加载的时候就完成了单例对象的实例化,那么如果至始至终从未使用该实例,就造成了内存的浪费
**/
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
class Singleton2 {
/**
* 懒汉模式
* 在第一次调用getInstance()方法时对静态对象进行初始化,虽然节约了资源,但是第一次初始化会慢一点
* 此外,如果多个线程调用此方法,就可能会new 出多个对象,无法工作
**/
private static Singleton2 instance;
private Singleton2() {
}
public static Singleton2 getInstance() {
if (null == instance) {
instance = new Singleton2();
}
return instance;
}
}
class Singleton3 {
/**
* 懒汉模式
* 可在多线程中正常工作,但是每一个getInstance方法都需要同步,造成了不必要的开销,而且大多时候我们不需要同步
* 所以不推荐使用该方法**/
private static Singleton3 instance;
private Singleton3(){
}
public static synchronized Singleton3 getInstance(){
if (null==instance){
instance=new Singleton3();
}
return instance;
}
}
class Singleton4{
/**double check双重检查模式(DCL)
*
* 1:是为了不必要的同步(如果instance已经被初始化过,那么就没必要再同步初始化对象)
* 2:锁保证了可见性,下面对instance的赋值,在退出同步后,instance的新值对别的线程是立刻可见的。
* 3:再一次非空判断是非常重要的,如果少了代码行3,其他线程由于依次通过了2,所以会各自创建各自的instance对象,单例模式失效
* 4:对象初始化,单线程中初始化对象没问题,但是多线程对正在初始化的对象的读写,由于初始化指令的重排序,会造成未完全
* 初始化就访问对象,造成不可控的问题。
*
* volatile是保证对象初始化的原子性,防止对象分配内存后,还没完全初始化,
* 而这时引用已经指向对象,同步块结束,另一个线程返回了instance,instance却还没初始化完成。
*
* double check过程描述:
* 比如说有100个线程同时调用getInstance方法,此时全部线程都进入getInstance的1,判断instance都为空之后
* ,全部线程都进入2,这时只有一个线程能够进入3,假设线程50进入了3,其他线程都暂时阻塞,线程50顺利经过3的判
* 断之后进入4,那么此时线程50拿到了Singleton4的初次初始化的对象instance,由于instance用了volatile,那么此
* 时instance的初始化指令不会被重排序,等instance对象完全初始化完之后,退出同步代码块,由于加锁
* 保证了instance的可见性,其他99条线程均看到了instance的新值,要么不会进入同步代码块,要么进入后立刻跳出
* 并返回正确的对象。
**/
private volatile static Singleton4 instance;
private Singleton4(){
}
public static Singleton4 getInstance(){
if (instance==null){//1
synchronized (Singleton4.class){//2
if (instance==null){//3
instance=new Singleton4();//4
}
}
}
return instance;
}
}
class Singleton5{
/**
* 静态内部类单例模式
* 第一次加载Singleton5类的时候不会初始化instance,只有调用getInstance方法时,虚拟机加载
* SingletonHolder,并直接初始化instance.
* 优点:不仅能保证线程安全(SingletonHolder类只会加载一次,
* 那么private static final Singleton5 instance=new Singleton5();就只调用一次),而且还能
* 保证Singleton5类的唯一性**/
private Singleton5(){
}
public static Singleton5 getInstance(){
return SingletonHolder.instance;
}
private static class SingletonHolder{
private static final Singleton5 instance=new Singleton5();
}
}
关于内部类和静态内部类何时被加载:加载一个类时,其内部类是否同时被加载?静态内部类单例模式