zoukankan      html  css  js  c++  java
  • 04-单例模式的几种写法

    示例中的SingleUtil类是个空类, 只是为了模拟创建单例的存在而已....

    懒汉式

    package demo.java.jiangkd.singleton.example;
    
    /**
     * 懒汉式<br>
     * 懒汉模式中单例是在需要的时候才去创建的,如果单例已经创建,再次调用获取接口将不会重新创建新的对象,而是直接返回之前创建的对象<br>
     * 好处是更启动速度快、节省资源,一直到实例被第一次访问,才需要初始化单例<br>
     * 但是这里的懒汉模式并没有考虑线程安全问题,在多个线程可能会并发调用它的getInstance()方法,导致创建多个实例
     * 
     * @author jiangkd
     * @date 2020/09/10
     */
    public class SingleDemo1 {
    
        private SingleDemo1() {}
    
        private static SingleUtil singleUtil = null;
    
        public static SingleUtil getInstance() {
            //
            if (null == singleUtil) {
                singleUtil = new SingleUtil();
            }
            return singleUtil;
        }
    }

    饿汉式

    package demo.java.jiangkd.singleton.example;
    
    /**
     * 饿汉式<br>
     * 饿汉模式是最简单的一种实现方式,饿汉模式在类加载的时候就对实例进行创建,实例在整个程序周期都存在。<br>
     * 好处是只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免了多线程同步的问题<br>
     * 缺点也很明显,即使这个单例没有用到也会被创建,而且在类加载之后就被创建,内存就被浪费了。<br>
     * 值得注意的时,单线程环境下,饿汉与懒汉在性能上没什么差别;但多线程环境下,由于懒汉需要加锁,饿汉的性能反而更优。
     * 
     * @author jiangkd
     * @date 2020/09/10
     */
    public class SingleDemo2 {
    
        private SingleDemo2() {}
    
        private static SingleUtil singleUtil = new SingleUtil();
    
        public static SingleUtil getInstance() {
            //
            return singleUtil;
        }
    }

    懒汉加锁式

    package demo.java.jiangkd.singleton.example;
    
    /**
     * 懒汉加锁式<br>
     * 加锁的懒汉模式看起来即解决了线程并发问题,又实现了延迟加载,然而它存在着性能问题,依然不够完美<br>
     * synchronized修饰的同步方法比一般方法要慢很多,如果多次调用getInstance(),累积的性能损耗就比较大了
     * 
     * @author jiangkd
     * @date 2020/09/10
     */
    public class SingleDemo3 {
    
        private SingleDemo3() {}
    
        private static SingleUtil singleUtil = null;
    
        /**
         * 方法进行加锁
         * 
         * @return
         */
        public static synchronized SingleUtil getInstance() {
            //
            if (null == singleUtil) {
                singleUtil = new SingleUtil();
            }
            return singleUtil;
        }
    }

    懒汉双重加锁式

    package demo.java.jiangkd.singleton.example;
    
    /**
     * 懒汉双重加锁式<br>
     * 为了防止new SingleUtil被执行多次,因此在new操作之前加上Synchronized 同步锁,锁住整个类(注意,这里不能使用对象锁)<br>
     * 进入Synchronized 临界区以后,还要再做一次判空。因为当两个线程同时访问的时候,线程A构建完对象,线程B也已经通过了最初的判空验证,不做第二次判空的话,线程B还是会再次构建instance对象<br>
     * JVM编译器的指令重排会导致并发问题,所以加入volatile关键字防止指令重排
     * 
     * @author jiangkd
     * @date 2020/09/10
     */
    public class SingleDemo4 {
    
        private SingleDemo4() {}
    
        /**
         * 使用volatile修饰
         */
        private static volatile SingleUtil singleUtil = null;
    
        /**
         * 代码块进行加锁
         * 
         * @return
         */
        public static SingleUtil getInstance() {
            //
            if (null == singleUtil) {
                synchronized (SingleDemo4.class) {
                    if (null == singleUtil) {
                        singleUtil = new SingleUtil();
                    }
                }
            }
            return singleUtil;
        }
    }

    静态内部类

    package demo.java.jiangkd.singleton.example;
    
    /**
     * 静态内部类<br>
     * 利用了类加载机制来保证只创建一个instance实例<br>
     * 与饿汉模式一样,也是利用了类加载机制,因此不存在多线程并发的问题<br>
     * 不一样的是,它是在内部类里面去创建对象实例<br>
     * 这样的话,只要应用中不使用内部类,JVM就不会去加载这个单例类,也就不会创建单例对象,从而实现懒汉式的延迟加载<br>
     * 也就是说这种方式可以同时保证延迟加载和线程安全
     * 
     * @author jiangkd
     * @date 2020/09/10
     */
    public class SingleDemo5 {
    
        private SingleDemo5() {}
    
        private static class SingleUtilHolder {
            public static SingleUtil instance = new SingleUtil();
        }
    
        public static SingleUtil getInstance() {
            //
            return SingleUtilHolder.instance;
        }
    }

    枚举

    package demo.java.jiangkd.singleton.example;
    
    /**
     * 枚举<br>
     * 用枚举实现单例模式,相当好用,但可读性是不存在的<br>
     * 丑陋但好用的语法糖
     * 
     * @author jiangkd
     * @date 2020/09/10
     */
    public enum SingleDemo6 {
    
        INSTANCE;
    
        private SingleUtil singleUtil;
    
        private SingleDemo6() {
            singleUtil = new SingleUtil();
        }
    
        public SingleUtil getInstance() {
            return singleUtil;
        }
    
        public static void main(String[] args) {
            //
            SingleUtil singleUtil = SingleDemo6.INSTANCE.getInstance();
        }
    }
  • 相关阅读:
    适合 C++ 新手学习的开源项目——在 GitHub 学编程
    原生JS封装常用函数
    C# 将excel文件导入到SqlServer数据库
    热配置的部署以及容易失败原因
    连接真机开发安卓(Android)移动app MUI框架 添加购物车等——混合式开发(四)
    标志寄存器06 零基础入门学习汇编语言59
    指针07 零基础入门学习C语言47
    标志寄存器05 零基础入门学习汇编语言58
    标志寄存器03 零基础入门学习汇编语言56
    标志寄存器04 零基础入门学习汇编语言57
  • 原文地址:https://www.cnblogs.com/no-celery/p/13645370.html
Copyright © 2011-2022 走看看