欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

说说单例模式!

程序员文章站 2022-03-06 15:57:27
单例模式定义确保一个类只有一个实例,并且提供该实例的全局访问点,就是这个类只能被new一次,并且每次都是用的new的这个。类结构一个私有的构造方法,一个私有的静态的实例变量,一个公有的静态函数,用来获取实例。私有构造方法:可以不让别人创建共有的静态函数:该实例的全局访问点,返回唯一的私有的静态实例变量具体实现懒汉式-线程不安全懒汉式就是用到的时候才创建返回对象,不用到的时候不会创建,但也存在线程不安全的问题线程不安全:多个线程同时第一次访问获取对象,都判断为空,然后都new了对象,导致多...

单例模式

定义

确保一个类只有一个实例,并且提供该实例的全局访问点,就是这个类只能被new一次,并且每次都是用的new的这个。

类结构

一个私有的构造方法,一个私有的静态的实例变量,一个公有的静态函数,用来获取实例。

私有构造方法:可以不让别人创建

共有的静态函数:该实例的全局访问点,返回唯一的私有的静态实例变量

具体实现

懒汉式-线程不安全

懒汉式就是用到的时候才创建返回对象,不用到的时候不会创建,但也存在线程不安全的问题

线程不安全:多个线程同时第一次访问获取对象,都判断为空,然后都new了对象,导致多次实例化对象

public class Singleton {

    private static Singleton uniqueInstance;

    private Singleton(){

    }

    public static Singleton getUniqueInstance(){
        if (uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}
懒汉式-线程安全

如何解决懒汉式的线程不安全问题呢?使其变为线程安全的,只需要在获取实例的时候加锁就行,这样同一时间只能有一个线程进入获取实例的方法,就可以避免线程不安全问题了!

缺点:由于加锁了,导致同一时间只能有一个线程访问这个方法,有性能问题,不建议使用。

public static synchronized Singleton getUniqueInstance(){
        if (uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
饿汉式-线程安全

也是为了解决懒汉式的线程不安全问题,直接实例化就行,不再使用延迟实例化,但是没有延迟实例化能节约资源

public class Singleton {

    private static Singleton uniqueInstance = new Singleton();

    private Singleton(){

    }

    public static synchronized Singleton getUniqueInstance(){
        return uniqueInstance;
    }
}
双重校验锁-线程安全

就是在实例化的时候进行加锁即可,不在方法上进行加锁了

public class Singleton {

    private volatile static Singleton uniqueInstance;

    private Singleton(){

    }

    public static  Singleton getUniqueInstance(){
        if (uniqueInstance == null){
            synchronized (Singleton.class){
                if (uniqueInstance == null){
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

首先解释为什么用volatile关键字

禁止jvm的指令重排,首先实例化一个对象分为三个步骤

  1. 分配内存空间
  2. 初始化对象
  3. 将对象指向分配的内存地址

这个顺序在jvm中执行式有可能乱序的,比如会132这样执行,当一个线程执行完成13之后,另一个线程刚好进入if判断不为空,直接就返回了一个未初始化的对象,所以为了解决这个问题使用volatile关键字可以禁止指令重排

再解释为什么用两个if

当两个线程同时进入第一个if,都判断不为空,然后上锁,一个线程进行实例化对象操作,实例化完毕后,另一个线程也加锁进入,但是如果没有第二个if的话,第二个进程还会进行实例化,加上之后就不会进行第二次实例化了。

静态内部类实现-线程安全

就是使用一个静态内部类,类中写一个静态常量,Singleton类被加载的时候并不会调用内部类,只有需要获取实例的时候才会调用内部类进行获取。

实现了延迟实例化+线程安全

public class Singleton {

    private Singleton(){

    }

    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }

    public static  Singleton getUniqueInstance(){
        return SingletonHolder.INSTANCE;
    }
}

本文地址:https://blog.csdn.net/hsunnyc/article/details/107618315

相关标签: 设计模式 java