• 设计模式单例模式饿汉式单例模式、懒汉式单例模式、静态内部类在Java中的使用示例


    场景

    设计模式-简单工厂模式、工厂模式、抽象工厂模式在Java中的使用示例:

    https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/127539695

    上面讲了工厂模式在Java中使用示例,下面讲单例模式的实现。

    单例模式(Singleton Pattern)

    是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。

    单例模式是创建型模式。

    单例模式在现实生活中应用比如公司CEO、部门经理等。

    注:

    博客:
    https://blog.csdn.net/badao_liumang_qizhi
    关注公众号
    霸道的程序猿
    获取编程相关电子书、教程推送与免费下载。

    实现

    饿汉式单例模式

    饿汉式单例模式在类加载的时候就立即初始化,并且创建单例对象。

    它绝对线程安全,在线程还没出现以前就实例化了,不存在访问安全问题。

    优点:

    没有加任何锁,执行效率高。

    缺点:

    类加载的时候就初始化,用不用都占空间,浪费内存。

    示例代码一:

    package com.ruoyi.demo.designPattern.hungrySingleton;
    
    /**
     * 饿汉式单例模式
     */
    public class HungrySingleton {
    
        //先静态、后动态;先属性、后方法;先上后下
        //私有实例,类初始化就加载
        private static final HungrySingleton hungrySingleton = new HungrySingleton();
        //私有构造方法
        //将构造方法设置为private后,外部程序无法访问此方法去实例化一个对象,确保只有自身能实例化
        private HungrySingleton(){};
        //公共的、静态的获取实例方法
        public static HungrySingleton getInstance(){
            return  hungrySingleton;
        }
    }

    示例代码二(利用静态代码块的机制):

    package com.ruoyi.demo.designPattern.hungrySingleton;
    
    public class HungrySingletonWithStatic {
    
        private static final HungrySingletonWithStatic hungrySingleton;
        //静态代码块,随着类的加载而执行,而且只执行一次
        static {
            hungrySingleton = new HungrySingletonWithStatic();
        }
        private HungrySingletonWithStatic(){};
        //公共的、静态的获取实例方法
        public static HungrySingletonWithStatic getInstance(){
            return  hungrySingleton;
        }
    }

    饿汉式单例模式适用于单例对象较少的情况。

    懒汉式单例模式

    懒汉式单例模式特点:

    被外部类调用的时候内部类才会加载。

    新建一个简单实现

    package com.ruoyi.demo.designPattern.lazySimpleSingleton;
    
    /**
     * 懒汉式单例模式:被外部类调用时内部类才会加载
     */
    public class LazySimpleSingleton {
    
        private static LazySimpleSingleton lazySimpleSingleton = null;
    
        private LazySimpleSingleton(){}
        //静态块,公共内存区域
        public  static LazySimpleSingleton getInstance(){
            if(lazySimpleSingleton == null){
                //没有被初始化就锁住当前类模板
                synchronized(LazySimpleSingleton.class){
                    if(lazySimpleSingleton == null){
                        lazySimpleSingleton = new LazySimpleSingleton();
                    }
                }
            }
            return lazySimpleSingleton;
        }
    }

    这里为啥要加synchronized,是因为这种方式存在线程安全隐患。下面会进行验证。

    新建一个线程类ExecutorThread

    package com.ruoyi.demo.designPattern.lazySimpleSingleton;
    
    public class ExecutorThread implements Runnable{
    
        @Override
        public void run() {
            LazySimpleSingleton simpleSingleton = LazySimpleSingleton.getInstance();
            System.out.println(Thread.currentThread().getName()+""+simpleSingleton);
        }
    }

    客户端测试代码

    package com.ruoyi.demo.designPattern.lazySimpleSingleton;
    
    public class LazySimpleSingletonTest {
        public static void main(String[] args) {
            Thread t1 = new Thread(new ExecutorThread());
            Thread t2 = new Thread(new ExecutorThread());
            t1.start();
            t2.start();
            System.out.println("结束");
        }
    }

    运行上面加了synchronized的代码,可以发现两个线程结果都是一样的。

    如果将synchronized去掉

    package com.ruoyi.demo.designPattern.lazySimpleSingleton;
    
    /**
     * 懒汉式单例模式:被外部类调用时内部类才会加载
     */
    public class LazySimpleSingleton {
    
        private static LazySimpleSingleton lazySimpleSingleton = null;
    
        private LazySimpleSingleton(){}
        //静态块,公共内存区域
        public  static LazySimpleSingleton getInstance(){
            if(lazySimpleSingleton == null){
                //没有被初始化就锁住当前类模板
                //synchronized(LazySimpleSingleton.class){
                    //if(lazySimpleSingleton == null){
                        lazySimpleSingleton = new LazySimpleSingleton();
                    //}
                //}
            }
            return lazySimpleSingleton;
        }
    }

    此时会出现两种不同结果

    静态内部类方式

    用到synchnorized关键字要上锁,对程序性能存在影响。

    可以采用静态内部类的方式

    package com.ruoyi.demo.designPattern.innerSingleton;
    
    /**
     * 兼顾饿汉式单例模式的内存浪费和synchnorized的性能问题,可以屏蔽这两个缺点
     */
    public class LazyInnerClassSingleton {
    
        //使用LazyInnerClassSingleton的时候,默认会先初始化内部类
        //如果没使用,则内部类是不加载的
        private LazyInnerClassSingleton(){}
        //static是为了使单例的空间共享,保证这个方法不会被重写、重载
        public static final LazyInnerClassSingleton getInstance(){
            //在返回结果以前,一定会加载内部类
            return LazyHolder.LAZY;
        }
    
        //默认不加载
        private static class LazyHolder{
            private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
        }
    }
  • 相关阅读:
    关于类加载
    Java垃圾回收机制复习
    关于网络协议
    hadoop
    dubbo框架原理
    经典场景的设计方案整理
    报告撰写,linux使用gimp简单做gif动图
    《Linux命令行与shell脚本编程大全 第3版》创建实用的脚本---11
    《Linux命令行与shell脚本编程大全 第3版》创建实用的脚本---10
    《Linux命令行与shell脚本编程大全 第3版》创建实用的脚本---07
  • 原文地址:https://www.cnblogs.com/badaoliumangqizhi/p/16832692.html
Copyright © 2020-2023  润新知