设计模式之单例模式

268 阅读3分钟
把设计模式撸一遍,先从简单的开始。

单例模式怕是面试常考的模式之一了。动不动就让你写个单例模式。

首先来了解一下单例模式,可以理解为单例模式就是整个程序运行到结束这个实例只有0或者1个。说到这来,就必须考虑另一个东西,就是多线程的时候。像ArrayList。当CPU运行速度加上线程访问多的时候,怎么保证这个对象的实例只存在1或者0呢。单例模式就是了解决这些。

单例模式基本写法:

1:构造器方法设置private,不能让外部new实例化

2:一个static方法返回实例,总得让外部使用

知道这两点就好写了。

饿汉模式:还没有开始,就实例化。通常是用

private static 类名 ; 静态字段

public class Singleton {

    /**
     * 静态 属性 类加载的时候就实例化 对象
     */
    private final static Singleton INSTANCE = new Singleton();

    private Singleton(){
    }

    public static Singleton getInstance(){
        return INSTANCE;
    }

}

在类加载的时候就完成实例化。没有做到延迟加载。

也可以用静态代码块

public class Singleton2 {

    private static Singleton2 singleton2;

    static {
        singleton2 = new Singleton2();
    }

    private Singleton2(){}

    public static Singleton2 getInstance(){
        return singleton2;
    }
}

学习单例模式,也可以顺带熟悉一下类的加载顺序。

说完饿汉模式,再说说懒汉模式,可以理解为。让它动一下,才去实例化,懒汉模式是为了延迟加载出现的。

public class Singleton4 {

    private static Singleton4 singleton4 ;

    private Singleton4(){}

    private static Singleton4 getSingleton4(){
        if (singleton4 == null){
            singleton4 = new Singleton4();
        }
        return singleton4;
    }
}

在实例化的时候,对对象做了一下空判断,当没有这个实例的时候再创建实例。但这个也就有有个问题。饿汉模式,可以看到它对对象的实例只会有一次,虽然懒汉模式是做了空判断,再去实例化,但是在多线程的情况下就可能出现两种实例。

private static synchronized Singleton5 getSingleton5(){    if (singleton5 == null){
    
            singleton5 = new Singleton5();

    }
    return singleton5;
}

在调用方法的时候执行同步代码块。效率太低了

private static  Singleton5 getSingleton5(){
    if (singleton5 == null){
//A线程进入 去实例化 A还没有实例化完成时 B线程相继进入
        synchronized(Singleton5.class){
            singleton5 = new Singleton5();
        }
    }
    return singleton5;
}

在判断空后做加锁处理,当通过了 == null 判断,第二条也进来了,变会出现多个实例但也可能还出现多个实例。

最好的方法便是双层锁

public static Singleton6 getSingleton6(){
    if (singleton6 == null){
        synchronized (Singleton6.class){
            if (singleton6 == null){
                singleton6 = new Singleton6();
            }
        }
    }
    return singleton6;
}

这样判断第一个是否有实例没有存在。有两条线程同时通过的时候,A线程创建完成。能及时锁住。

还有一种 是静态类部

public class Singleton7 {

    private Singleton7(){}

    private static class SingletonInstance{
        static {
            System.out.println("SingletonInstance");
        }
        private static final Singleton7 INSTANCE = new Singleton7();
    }

    public static Singleton7 getInstance(){
        System.out.println("getInstance");
        return SingletonInstance.INSTANCE;
    }

}

在外部调用的时候,去调用静态类部类,只有调用的时候,静态类部类才实例化。而静态类部类也像是饿汉模式一样,对于静态内部类没有延迟加载,但是对于Singleton7对来说是有延迟加载的。

基本都是在下面的链接学的,标准请看下面的,谢谢:

单例模式的八种写法比较