面试中总会问到设计模式,但是,对于应届生来说,最见到那的也是问得最多的就是单例模式,更有甚者直接在手撕代码的时候写单例模式,下面就让我们来看看单例模式都有哪些实现方式吧。
单例模式第一弹-----懒汉式
懒汉式,这种方式等到需要调用getInstance的时候才去初始化,这样有一个好处就是在一定程度上可以节省内存空间。但是也有一个坏处就是在多线程的环境下式不安全的。代码如下:
/**
* 懒汉模式,就是等到需要的时候采取初始化
* 在多线程的情况下是不安全的
*/
public class LazySingleton {
private static LazySingleton instace = null;
private LazySingleton() {
}
public static LazySingleton getInstace() {
if (instace == null) {
instace = new LazySingleton();
}
return instace;
}
}
多线程下测试的结果
虽然简单,但是我们发现确实是不安全的(实例的地址明显不对)。
单例模式第二弹----双检锁模式
其实双检锁就是懒汉模式的进阶版,你不是不安全嘛,于是我就让你安全呗,代码如下
/**
* 双检锁来实现单例模式,其实就是安全版本的懒汉式单例
*
* 如果不加入volatile可能会出现问题
* instance = new DoubleCheckSingleton();分为三个步骤
* 1.在堆内存开辟内存空间。
* 2.在堆内存中实例化SingleTon里面的各个参数。
* 3.把对象指向堆内存空间。
* 由于jvm可能存在优化的现象导致乱序执行,比如导致3比2先执行,那么,其他线程来获取的时候就会出错
*/
public class DoubleCheckSingleton {
private static volatile DoubleCheckSingleton instance = null;
private DoubleCheckSingleton(){}
public static DoubleCheckSingleton getInstance(){
if(instance==null){
synchronized (DoubleCheckSingleton.class){
if(instance == null){
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
单例模式第三弹----饿汉模式
饿汉模式,听名字就知道了,就是一上来就直接加载了,这样就可以避免线程不安全的问题,但是也是会有一个问题就是内存问题了呗。代码如下
/**
* 饿汉式单例模式,会在最开始就进行实例化,是线程安全的
*/
public class HangerSingleton {
private static HangerSingleton instance = new HangerSingleton();
private HangerSingleton() {
}
public static HangerSingleton getInstance() {
return instance;
}
}
单例模式第四弹----静态内部类
既然嫌弃饿汉模式不具有懒加载的功能,那么,静态内部类就完全满足这个功能,不但可以懒加载,还安全。代码如下
/**
* 外部类第一次加载的时候并不会加载静态内部类,直到调用getInstance的时候才会去实例化instance而且智慧去加载一次
*
*/
public class StaticInnerSingleton {
private StaticInnerSingleton() {
}
private static class StaticInnerSingletonHoler {
private static StaticInnerSingleton instance = new StaticInnerSingleton();
}
public static StaticInnerSingleton getInstance() {
return StaticInnerSingletonHoler.instance;
}
}
单例模式第五弹----枚举类
虽然静态内部类是很好了,但是我又嫌弃代码太长,怎么办呢???那就直接使用枚举类了呗,枚举天然就具备单例的特性,多清爽啊。
public enum EnumSingleton {
instance;
}
以上。。。。。