美文网首页程序员
Java设计模式之单例模式(看完不会你打我)

Java设计模式之单例模式(看完不会你打我)

作者: Negen | 来源:发表于2020-05-23 17:25 被阅读0次

    零、什么是单例模式?

    单例,单例,顾名思义这个类从头至尾只有一个实例。

    单例模式具备以下三个特点:

    • 私有化的构造函数

    • 私有的静态的全局变量

    • 公有的静态的方法

    常用的三种单例模式:

    • 懒汉模式(线程不安全)

    • 饿汉模式(线程安全,资源利用率不高)

    • 双重校验锁模式(线程安全,资源利用率高)

    一、懒汉模式(线程不安全)

    类加载的时候,“懒”的去创建一个实例;

    当第一次被使用的时候我才给你创建实例,延迟加载

    示例代码如下:

    /**
     *  懒汉式
     *  线程不安全,延迟初始化
     * @author :Negen
     * @Date :Created in 15:25 2020/5/23
     * @Description:
     * @Modified By:
     * @Version: 1.0
     */
    public class SingletonLazy {
        //私有的静态的全局变量
        private static SingletonLazy instanse;
        //私有化的构造函数
        private SingletonLazy(){};
        //公有的静态的方法
        public static SingletonLazy getInstance(){
            if (null == instanse){ //线程不安全触发点
                instanse = new SingletonLazy();
            }
            return instanse;
        }
    }
    

    二、饿汉模式(线程安全)

    类加载的时候就创建一个实例;

    创建的实例如果一直没有使用的话,就会造成资源浪费;

    实例代码如下:

    /**
     *  饿汉模式
     *  线程安全,常用
     *  一开始就创建了实例,如果一直没用,就是产生的垃圾
     * @author :Negen
     * @Date :Created in 15:30 2020/5/23
     * @Description:
     * @Modified By:
     * @Version: 1.0
     */
    public class SingletonHungary {
        private static SingletonHungary instance = new SingletonHungary();
        private SingletonHungary(){};
        public static SingletonHungary getInstance(){
            return instance;
        }
    }
    
    

    三、双重校验锁模式(线程安全)

    对实例进程两次是否为空的检查;

    第一次检查是为了防止不必要的锁;

    第二次就是例行检查;

    示例代码如下:

    /**
     *  双重检查模式
     *
     *  第一次:避免不必要的上锁
     *  第二次:例行检查
     * @author :Negen
     * @Date :Created in 16:28 2020/5/23
     * @Description:
     * @Modified By:
     * @Version: 1.0
     */
    public class SingletonDoubleCheckLock {
        private volatile static SingletonDoubleCheckLock instance;
        private SingletonDoubleCheckLock(){};
        public static SingletonDoubleCheckLock getInstance(){
            if (null == instance){
                synchronized (SingletonDoubleCheckLock.class){
                    if (null == instance){
                        instance = new SingletonDoubleCheckLock();
                    }
                }
            }
            return instance;
        }
    }
    

    四、线程不安全体现在哪儿?

    如果有两个线程同时进入 if(instance == null)阶段,那么它们都会进入创建实例的阶段,从而导致创建多个不同的实例。

    下面用多线程模拟了三种模式创建实例的结果

    1、懒汉模式

    示例代码:

    public class TestLazy implements Runnable{
        public static void main(String[] args) {
            for (int i = 0; i<10; i++){
                TestLazy test = new TestLazy();
                new Thread(test).start();
            }
        }
        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "----" + SingletonLazy.getInstance().toString());
        }
    }
    
    

    打印结果:

    懒汉模式结果.png

    十个线程中出现了三个不同的地址,说明“懒汉模式”线程不安全

    2、饿汉模式

    示例代码:

    public class TestHungary implements Runnable{
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++){
                TestHungary test = new TestHungary();
                new Thread(test).start();
            }
        }
        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "----" + SingletonHungary.getInstance().toString());
        }
    }
    

    打印结果:

    [图片上传失败...(image-34b196-1590225907614)]

    十个线程中出现的都是相同的地址,说明“饿汉模式”线程安全

    3、双重校验锁模式

    示例代码:

    public class TestDoubleCheckLock implements Runnable{
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++){
                TestDoubleCheckLock testDoubleCheckLock = new TestDoubleCheckLock();
                new Thread(testDoubleCheckLock).start();
    
            }
        }
    
        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "----" + SingletonDoubleCheckLock.getInstance().toString());
        }
    }
    

    打印结果:

    [图片上传失败...(image-96367b-1590225907614)]

    十个线程中出现的都是相同的地址,说明“双重校验锁模式”线程安全

    相关文章

      网友评论

        本文标题:Java设计模式之单例模式(看完不会你打我)

        本文链接:https://www.haomeiwen.com/subject/ajjlahtx.html