Design Pattern javaalready

JAVA单例模式

2022-02-25  本文已影响0人  墨宇暗黑

设计模式大题分为创建性模式,结构型模式,行为性模式

这节主要讲解单列模式,单列模式有以下八种创建方法:
1.饿汉式(静态常量)
2.饿汉式(静态代码块)
3.懒汉式(线程不安全)
4.懒汉式(线程安全,同步方法)
5.懒汉式(线程安全,同步代码块)
6.双重检查
7.静态内部类
8.枚举

1.饿汉式(静态常量)

优点就是写法比较简单,类装载的时候就完成了实例化,解决了类的同步问题
缺点:类装载就完成了类的初始化,可能这个类暂时不需要使用,这样就造成了内存浪费

public class SingletonTest01 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1==singleton2);
    }
}
class Singleton{
    private final static Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
}
2.饿汉式(静态代码块)

优点和缺点和静态常量一样

public class SingletonTest02 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1==singleton2);
    }
}
class Singleton{
    private final static Singleton instance;
    static {
        instance = new Singleton();
    }
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
}
3.懒汉式(线程不安全)

优点:线程使用的时候才进行加载,节约内存
缺点:线程不安全,在多线程的情况下有可能第一个线程进入if语句,但是还没有创建好,这个时候又进来第二个线程进行创建,那么他就创建了多个实例,破坏了单列模式的规则,

public class SingletonTest03 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1==singleton2);
    }
}
class Singleton{
    private static Singleton instance;
    private Singleton(){}
    public static Singleton getInstance(){
        if(instance==null){
            instance = new Singleton();
        }
        return instance;
    }
}
4.懒汉式(线程安全,同步方法)

优点:解决了线程安全问题
缺点:方法同步效率太低,不推荐使用

public class SingletonTest04 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1==singleton2);
    }
}
class Singleton{
    private static Singleton instance;
    private Singleton(){}
    public synchronized static Singleton getInstance(){
        if(instance==null){
            instance = new Singleton();
        }
        return instance;
    }
}
5.懒汉式(线程不安全,同步代码块)

多线程情况下可能会生成多个实例

public class SingletonTest05 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1==singleton2);
    }
}
class Singleton{
    private static Singleton instance;
    private Singleton(){}
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                instance = new Singleton();
            }
        }
        return instance;
    }
}
6.双重检查

首先来说,对于第一个if,只有在instance没有创建的情况下才能进去,也就是性能相对不错,即使第一个if有很多线程进来,但是对于synchronized只有一个线程可以进去,也就是对于进入第一个if的其他线程只有等待第一个线程执行完同步代码块,而且对于第一个线程执行完之后,其他线程在进去也不会创建实例了,所以他是延时加载,线程安全的

public class SingletonTest06 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1==singleton2);
    }
}
class Singleton{
    private static Singleton instance;
    private Singleton(){}
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
7.静态内部类

类装载是线程安全的,静态内部类只会在第一次使用的时候才会进行加载

public class SingletonTest07 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1==singleton2);
    }
}
class Singleton{
    private Singleton(){}
    private static class InnerSingleton{
        public static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance(){
        return InnerSingleton.INSTANCE;
    }
}
8.枚举

枚举本身就是单列的,所以不用考虑多线程安全这些安全问题(针对与单列模式)

public class SingletonTest08 {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.INSTANCE;
        Singleton singleton2 = Singleton.INSTANCE;
        System.out.println(singleton1==singleton2);
        singleton1.sayOK();
    }
}
enum Singleton{
    INSTANCE;
    public void sayOK(){
        System.out.println("ok~");
    }
}

什么时候会使用单列模式:需要频繁创建和销毁的对象,创建对象耗时过多或耗费资源过多(重量级对象),但又经常用到的对象,工具类对象,频繁访问数据库或文件的对象(比如数据源,session等)

在JDK中的Runtime采用了单列模式,使用了饿汉式静态常量来进行创建


image.png

可以用到单例模式的地方线程池,数据库连接池,Spring里的IOC容器默认就是单例模式采用了ConcurrentHashMap存储bean

上一篇下一篇

猜你喜欢

热点阅读