美文网首页
单例模式

单例模式

作者: 金煜博 | 来源:发表于2021-05-05 11:20 被阅读0次

    什么是单例模式?

    保证jvm中只能有一个实例

    1.饿汉式

    提前创建对象,保证了线程的安全,占内存空间,影响程序启动效率

    示例代码

    public class Singleton {
        public  static Singleton singleton = new Singleton();
        private Singleton() {
        }
        public static Singleton getInitial(){
            return singleton;
        }
    }
    
    public class V1 {
        public static void main(String[] args) {
            Singleton singleton1 = Singleton.getInitial();
            Singleton singleton2 = Singleton.getInitial();
            System.out.println(singleton1==singleton2);
        }
    }
    

    2.懒汉式

    需要用到时才创建对象实例,因为在方法上加了锁,导致创建和获取对象都上了锁,效率低。

    示例代码

    public class Singleton {
        private static Singleton singleton;
        //私有的构造方法可以禁止new对象
        private Singleton() {
    
        }
    
         //在方法上加锁导致读写操作都上锁了效率低,成了单线程了
         public static synchronized Singleton  getInitial(){
             try {
                 Thread.sleep(3000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
            if(singleton==null){
                singleton = new Singleton();
            }
            return singleton;
         }
    }
    
    public class V2 {
       //创建100个线程模拟执行效率和线程是否安全
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Singleton singleton1 =  Singleton.getInitial();
                        System.out.println(Thread.currentThread().getName()+"-----------"+singleton1);
                    }
                }).start();
            }
        }
    }
    

    3.双重检验锁

    双重检验锁解决了在写上锁,读不上锁,有效的提高执行效率
    (重点理解下两个if判断的意义)

    示例代码

    public class Singleton {
        private static Singleton singleton;
        //私有的构造方法可以禁止new对象
        private Singleton() {
    
        } 
        //在代码段上加锁,只是在创建Singleton时上锁,读取时无锁。(双重检验锁)
        public static Singleton getInitial() {
            //第一个if判断singleton是否null不是就可以直接读取singleton对象
            if (singleton == null) {
                synchronized (Singleton.class) {
                    //第二个if判断防止多个线程同时拿到锁后,重复创建singleton对象
                    if (singleton == null) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
    }
    
    public class V2 {
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Singleton singleton1 =  Singleton.getInitial();
                        System.out.println(Thread.currentThread().getName()+"-----------"+singleton1);
                    }
                }).start();
            }
        }
    }
    

    4.静态类部内

    静态内部内结合了懒汉式和饿汉式的优,效率高

    示例代码

    public class Singleton {
        private Singleton() {
            System.out.println("-----------初始化构造函数-------");
        }
    
        private static  Singleton initialSingleton(){
            return GetSingleton.singleton;
        }
    
        private static class GetSingleton{
            private  final  static  Singleton singleton =  new Singleton();
        }
    
        public static void main(String[] args) {
            System.out.println("开始运行");
            Singleton singleton1 =  Singleton.initialSingleton();
            Singleton singleton2 =  Singleton.initialSingleton();
            System.out.println(singleton1==singleton2);
        }
    
    

    5.枚举

    使用枚举方式可以有效的防止反射机制和序列化,因为jdk底层源码中有if判断禁用了反射与序列化

    public enum  Singleton {
        SL;
        public   void show(){
            System.out.println("枚举单例模式可以防止反射和序列化");
        }
    }
    
    public class V4 {
        public static void main(String[] args) {
            Singleton singleton1 = Singleton.SL;
            Singleton singleton2 = Singleton.SL;
            System.out.println(singleton1 == singleton2);
            singleton1.show();
        }
    }
    

    6.单例模式额外注意点

    1.使用反射机制可以破解单例
    2.使用序列化可以破解单例
    3.可以在无参构造方法中判断单例对象是否为null,是就抛出异常
    4.不用懒加载的话用饿汉式,反之用静态类部内方式,需要序列化的对象用枚举方式

    相关文章

      网友评论

          本文标题:单例模式

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