zoukankan      html  css  js  c++  java
  • 设计模式-单例模式

    单例模式模式一般大家都会认为它比较简单,其实并非你们所认为的那样,很多情况下,单例模式会涉及到很多优化,下面给大家简单介绍一下单例模式的几种演变过程:

    • 饿汉模式
    • 懒汉模式 
    • 懒汉模式(加锁关键字 synchronized)
    • 懒汉模式(细粒度的添加synchronized)
    • 懒汉模式(双重检查)
    • 静态内部类
    • 枚举类

    第一种:饿汉模式  比较简单,类加载到内存的时候就进行实例化,推荐使用 ,但是有人会说,既然不用干嘛要进行实例化;

    package com.dongl.singleton;
    
    /**
     * 饿汉模式
     * 类加载到内存就直接实例化一个单例,JVM会保证它的线程安全
     * 简单使用 推荐使用
     * 缺点:无论用到与否 类加载就会直接实例化
     * 有人就会吹毛求疵说:你不用 你实例化干嘛?
     */
    public class T01_Singleton {
        private static T01_Singleton INSTANCE = new T01_Singleton();
    
        public T01_Singleton() {
        }
    
        public static T01_Singleton  getInstance(){
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            T01_Singleton t1 = T01_Singleton.getInstance();
            T01_Singleton t2 = T01_Singleton.getInstance();
            System.out.println(t1 == t2);
        }
    }

    第二种:懒汉模式 这种模式在多线程的情况下会出现问题

    package com.dongl.singleton;
    
    
    /**
     * 懒汉模式 lazy loading
     * 虽然达到了按需初始化的目的 但是也带来了线程安全的问题
     * 在多线程的情况下
     */
    public class T02_Singleton {
        private static T02_Singleton INSTANCE = null;
    
        public T02_Singleton() {
        }
    
        public static T02_Singleton getInstance(){
            if(INSTANCE == null){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                INSTANCE =  new T02_Singleton();
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) {
    //        T02_Singleton t1 = T02_Singleton.getInstance();
    //        T02_Singleton t2 = T02_Singleton.getInstance();
    //        System.out.println(t1 == t2);
    
            /**创建100个线程 调用getInstance() 打印返回的对象的hashcode()*/
            for (int i = 0; i < 100; i++) {
                new Thread(()->{
                    System.out.println(T02_Singleton.getInstance().hashCode());
                }).start();
            }
        }
    }

    //运行结果 hashcode值不相同

    E:JDKjdk1.8injava.exe "-javaagent:E:IdeaIntelliJ IDEA
    1365279759
    1365279759
    1365279759
    1945255694
    226994615

    
    

    第三种:懒汉模式(加锁关键字 synchronized)这种方式解决了懒汉模式下多线程问题,但是同时带来的问题是效率降低;

    package com.dongl.singleton;
    
    
    /**
     * 懒汉模式 lazy loading
     * 虽然达到了按需初始化的目的 但是也带来了线程安全的问题
     * 解决办法使用synchronized 但是带来的问题就是效率下降
     */
    public class T03_Singleton {
        private static T03_Singleton INSTANCE = null;
    
        public T03_Singleton() {
        }
    
        /**
         * 加锁的方式有两种 一种是对方法进行加锁 另一种是对代码块进行加锁
         * 涉及到的无非是锁的粒度问题
         * @return
         */
        public static /**synchronized*/ T03_Singleton getInstance(){
            synchronized (T02_Singleton.class) {
                if (INSTANCE == null) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new T03_Singleton();
                }
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            /**创建100个线程 调用getInstance() 打印返回的对象的hashcode()*/
            for (int i = 0; i < 100; i++) {
                new Thread(()->{
                    System.out.println(T03_Singleton.getInstance().hashCode());
                }).start();
            }
        }
    }

    第四种:懒汉模式(细粒度的添加synchronized)试图通过减小锁的粒度来进行改善效率的问题 但是不可行;

    package com.dongl.singleton;
    
    
    /**
     * 懒汉模式 lazy loading
     * 虽然达到了按需初始化的目的 但是也带来了线程安全的问题
     * 解决办法使用synchronized 但是带来的问题就是效率下降
     *
     * 试图通过减小锁的粒度来进行改善效率的问题  但是不可行
     */
    public class T04_Singleton {
        private static T04_Singleton INSTANCE = null;
    
        public T04_Singleton() {
        }
    
        public static /**synchronized*/ T04_Singleton getInstance(){
            if (INSTANCE == null) {
                //试图通过减小锁的粒度来进行改善效率的问题  但是不可行
                synchronized (T02_Singleton.class) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new T04_Singleton();
                }
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            /**创建100个线程 调用getInstance() 打印返回的对象的hashcode()*/
            for (int i = 0; i < 100; i++) {
                new Thread(()->{
                    System.out.println(T04_Singleton.getInstance().hashCode());
                }).start();
            }
        }
    }

    第五种:懒汉模式(双重检查)这种方式解决了多线程带来的问题;

    package com.dongl.singleton;
    
    
    /**
     * 懒汉模式 lazy loading
     * 虽然达到了按需初始化的目的 但是也带来了线程安全的问题
     * 解决办法使用synchronized 但是带来的问题就是效率下降
     * 因为锁的粒度很小也会带来多线程问题
     * 这时可以使用双重检查 来避免
     */
    public class T05_Singleton {
        private volatile static T05_Singleton INSTANCE = null;
    
        public T05_Singleton() {
        }
    
        public static /**synchronized*/
        T05_Singleton getInstance(){
            if (INSTANCE == null) {
                synchronized (T02_Singleton.class) {
                    //双重检查
                    if(INSTANCE == null) {
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        INSTANCE = new T05_Singleton();
                    }
                }
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            /**创建100个线程 调用getInstance() 打印返回的对象的hashcode()*/
            for (int i = 0; i < 100; i++) {
                new Thread(()->{
                    System.out.println(T05_Singleton.getInstance().hashCode());
                }).start();
            }
        }
    }

    第六种:静态内部类实现懒加载(lazy loading)这种方式是最优解之一  因为在加载类的时候 不加载内部类这样就实现了懒加载;

    package com.dongl.singleton;
    
    
    /**
     * 静态内部类的法方法
     * JVM保证单例
     * 加载外部类的时候 不会加载内部类 这样实现了懒加载
     */
    public class T06_Singleton {
    
        public T06_Singleton() {
        }
    
        //静态内部类
        private static class T06_SingletonHandler{
            private final static T06_Singleton INSTANCE = new T06_Singleton();
        }
    
        public static T06_Singleton getInstance(){
            T06_Singleton instance = T06_SingletonHandler.INSTANCE;
            return instance;
        }
    
        public static void main(String[] args) {
            /**创建100个线程 调用getInstance() 打印返回的对象的hashcode()*/
            for (int i = 0; i < 100; i++) {
                new Thread(()->{
                    System.out.println(T06_Singleton.getInstance().hashCode());
                }).start();
            }
        }
    }

    第七种:枚举类  不仅可以解决线程同步,还可以防止反序列化。

    package com.dongl.singleton;
    
    
    /**
     * 不仅可以解决线程同步,还可以防止反序列化。
     */
    public enum  T07_Singleton {
    
        INSTANCE;
    
        public static void main(String[] args) {
            /**创建100个线程 调用getInstance() 打印返回的对象的hashcode()*/
            for (int i = 0; i < 100; i++) {
                new Thread(()->{
                    System.out.println(T07_Singleton.INSTANCE.hashCode());
                }).start();
            }
        }
    }

    以上其中方式是按照问题出现 一步步的优化得到的,如果你觉得有疑问可以评论区说出你的观点,一起讨论一起进步!!!

  • 相关阅读:
    bzoj 1176 cdq分治套树状数组
    Codeforces 669E cdq分治
    Codeforces 1101D 点分治
    Codeforces 1100E 拓扑排序
    Codeforces 1188D Make Equal DP
    Codeforces 1188A 构造
    Codeforces 1188B 式子转化
    Codeforces 1188C DP 鸽巢原理
    Codeforces 1179D 树形DP 斜率优化
    git commit -m "XX"报错 pre -commit hook failed (add --no-verify to bypass)问题
  • 原文地址:https://www.cnblogs.com/dongl961230/p/13298631.html
Copyright © 2011-2022 走看看