单例模式
由于是进阶,基础的饿汉式与懒汉式单例模式就不在这里说明了,双重检查的写法也没什么可讲的,算是高级一点放上代码吧,双重检查:
public class DoubleCheckSingleton {
//私有化构造方法
private DoubleCheckSingleton(){};
//自己作为属性: 添加volatile 修饰,使其对所有线程可见
private volatile static DoubleCheckSingleton instansce;
public static DoubleCheckSingleton getInstance(){
if (instansce==null){
synchronized (DoubleCheckSingleton.class){
if (instansce==null){
instansce=new DoubleCheckSingleton();
}
}
}
return instansce;
}
}
提一下,只有懒汉式才会有线程安全问题,饿汉式是没有的.
重点
下面这种方式是研磨设计模式中提到的一种非常巧妙的单例模式实现方法,先上代码:
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,
* 而且只有被调用到时才会装载,从而实现延迟加载.
*/
private static class SingletonHolder{
//静态初始化器,由JVM保证
private static Singleton instance = new Singleton();
}
//私有化构造方法
private Singleton(){};
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
上述方式的思路:
1.解决的问题:同时实现线程安全和延迟加载,并且不通过synchronized关键在加锁(影响访问效率);
2.解决思路:JVM有几种情况会隐式的进行同步控制:
- 由静态初始化器(在静态字段上或static{}代码块的初始化器)初始化数据时
- 访问final字段时
- 在创建线程之前创建对象时
- 线程可以看到它将要处理的对象时
我们使用的就是第一种情况,当getInstance方法第一次被调用的时候,它才会第一次 调用SingletonHolder.instance,导致SingletonHolder类得到初始化,而这个类在装载并被初始化的时候会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,所以只会在JVM加载类的时候初始化一次,并由虚拟机保证其安全性.这种写法的优势在于getInstance方法没有被同步,Singleton实例也只是在内部类被加载(getInstance方法第一次被调用的时候),才会装载一次,因此延迟初始化并没有增加任何访问成本.
最后,大招:
public enum Single {
singleTon;
public void oprate(String s){
System.out.println(s);
}
}