zoukankan      html  css  js  c++  java
  • 设计模式之一单例模式(java实现)

      学习一下各种设计模式,看以后的用不用得上╮(╯_╰)╭

    1. 饱汉式

    /**
     * 饱汉式
     * 1. 构造器私有化
     * 2. 静态的私有变量instance
     * 3. 静态的public方法
     */
    public class Singleton {
        private static Singleton instance = new Singleton();
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            return instance;
        }
    }

      懒汉式缺点:不管用不用这个对象,都会实例化,浪费资源;

    2 饿汉式

    /**
     * 饿汉式
     * 只有在需要获取实例的时候,才会去实例化
     */
    public class Singleton {
        private static Singleton instance;
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

      恶汉式也带来了问题,就是线程不安全

    3. 对饿汉式+synchronized 

    /**
     * 饿汉式+synchronized
     * 只有在需要获取实例的时候,才会去实例化
     */
    public class Singleton {
        private static Singleton instance;
        private Singleton() {
        }
    
        public synchronized static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

      在方法上加锁会锁住整个方法,继续优化一下,只是给new对象的部分代码加锁:

    /**
     * 饿汉式+synchronized同步代码块
     * 只有在需要获取实例的时候,才会去实例化
     */
    public class Singleton {
        private static Singleton instance;
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    instance = new Singleton();
                }
            }
            return instance;
        }
    }

      但是在同步代码块这样的方式有产生了问题:线程A和线程B都执行到了同步代码块这里,线程A先进去,实例化对象instance,释放锁,然后线程B才进去,于是也实例化了一个instance,于是就有两个实例了,线程不安全

    4. 双重检测锁

    /**
     * 双重检测锁
     * 
     */
    public 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;
        }
    }

      但是上面双重检测的方式在超高并发的环境下也有问题,涉及到JVM层面指令重排,这个双重检测单例模式加不加volatile是个经典面试题

      举个例子:Singleton instance = new Singleton() 这条指令虽然我们程序员看起来就是一条指令,但是在jvm层面却是会分解成三条
        (1)在java堆中分配空间,创建对象

       (2) 给创建的对象初始化赋值

       (3)在java栈中创建局部变量instance,指向java堆中的对象

      在上面(2)和(3)因为指令重排可能交换了顺序,执行过程就是(1)-->(3)-->(2),当线程A执行到(1)->(3)的时候,此时instance指向的是一个半成品的实例,因为这个实例中的属性值还没有初始化;

      此时线程B来调用Singleton.getInstance()就会发现跳过了里面的if语句,直接返回了instance实例,于是在线程B中调用该实例的方法的时候就会出问题(半成品的对象是什么呢,想一下类加载机制,加载,链接(验证,准备,解析),初始化,在加载,链接之后,初始化之前的对象就是半成品的)

      可以使用volatile关键字进行优化,禁止指令重排;

    5.1  双重检测锁+volatile实现单例(完美版)

    /**
     * 双重检测+volatile
     */
    public class Singleton {
        private static volatile Singleton instance;
        private Singleton() {
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
    
                }
            }
            return instance;
        }
    }

    5.2 枚举实现(完美版)

    /**
     * 枚举方式实现
     */
    public enum SingletonEnum {
        instance; 
    }

    5.3 静态内部类的方式实现单例(完美版)

    /**
     * 静态内部类实现单例
     */
    public class Singleton {
        private static Singleton instance;
        private Singleton() {
        }
    
        private static class SingletonHelper {
            private static final Singleton singleton = new Singleton();
        }
    
        public static Singleton getInstance() {
            return SingletonHelper.singleton;
        }
    }
    --------------以上皆原创,给未来的自己留下一点学习的痕迹!--------
  • 相关阅读:
    牛客 小a与星际探索 bfs
    gear gym 思维题
    dp Surf
    P1280 尼克的任务
    Codeforces Round #539 (Div. 2) C. Sasha and a Bit of Relax
    Codeforces Round #542 C. Connect 搜索
    Layui 文件上传 附带data数据
    Layui 隐藏左侧菜单
    Layui 关闭当前标签页
    Layui Iframe页面间 方法的相互调用
  • 原文地址:https://www.cnblogs.com/wyq1995/p/14461558.html
Copyright © 2011-2022 走看看