• java单例模式详解


    饿汉法

    饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。代码如下:

    1 public class Singleton {   
    2     private static Singleton = new Singleton();
    3     private Singleton() {}
    4     public static getSignleton(){
    5         return singleton;
    6     }
    7 }

    缺点:无法实现对象延时加载。

    懒汉法

    懒汉式就是需要使用该类的时候再创建对象实例(进而实现了对象的延时加载,减少了系统负荷)。

    1.单线程实现方式,代码如下:

    1 public class Singleton {
    2     private static Singleton singleton = null;
    3     private Singleton(){}
    4     public static Singleton getSingleton() {
    5         if(singleton == null) singleton = new Singleton();
    6         return singleton;
    7     }
    8 }

    缺点:线程不安全,如果有多条线程同时调用getSingleton()方法,就有很大可能导致重复创建对象。

    2.线程安全方式,代码如下:

     1 public class Singleton {
     2     private static volatile Singleton singleton = null;
     3     private Singleton(){}
     4     public static Singleton getSingleton(){
     5         synchronized (Singleton.class){
     6             if(singleton == null){
     7                 singleton = new Singleton();
     8             }
     9         }
    10         return singleton;
    11     }    
    12 }

    说明:使用volatile关键字进行限制,保证其对所有线程的可见性,并且禁止对其进行指令重排序优化。

    缺点:每次调用getSingleton()方法,都会因为synchronized关键字进行等待,效率低下。

    3.兼顾线程安全和效率方式,代码如下:

    public class Singleton {
        private static volatile Singleton singleton = null;
        private Singleton(){}
        public static Singleton getSingleton(){
            if(singleton == null){
                synchronized (Singleton.class){
                    if(singleton == null){
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }    
    }

    说明:“双重检查锁”,使用双判断null方式,可以减少线程进行等待,提高效率。

    扩展:

    方式2中说明:

    1.可见性:指的是在一个线程中对该变量的修改会马上由工作内存(Work Memory)写回主内存(Main Memory),所以会马上反应在其它线程的读取操作中。(工作内存是线程独享的,主存是线程共享的);

    2.重新排序:禁止指令重排序优化。我们写的代码(尤其是多线程代码),由于编译器优化,在实际执行的时候可能与我们编写的顺序不同。编译器只保证程序执行结果与源代码相同,却不保证实际指令的顺序与源代码相同。这在单线程看起来没什么问题,然而一旦引入多线程,这种乱序就可能导致严重问题。volatile关键字就可以从语义上解决这个问题。但是禁止指令重排优化这条语义直到jdk1.5以后才能正确工作。此前的JDK中即使将变量声明为volatile也无法完全避免重排序所导致的问题。所以,在jdk1.5版本前,双重检查锁形式的单例模式是无法保证线程安全的。)

    静态内部类法

    1 public class Singleton {
    2     private static class Holder {
    3         private static Singleton singleton = new Singleton();
    4     }
    5     private Singleton(){}
    6     public static Singleton getSingleton(){
    7         return Holder.singleton;
    8     }
    9 }

    优点:静态内部类只有在使用的时候才会被加载,不会随主类的加载而加载,实现了延时加载,静态内部类只会被加载一次,保证了线程安全。

    枚举写法

     1 public enum Singleton {
     2     INSTANCE;
     3     private String name;
     4     public String getName(){
     5         return name;
     6     }
     7     public void setName(String name){
     8         this.name = name;
     9     }
    10 }

    优点:防止用户使用反射方式调用私有构造器;提供了自动序列化机制,防止反序列化的时候创建新的对象。

  • 相关阅读:
    第二学期,第0次作业
    最后一次作业——总结报告
    第14、15周作业
    第七周作业
    第6周作业
    第四周作业
    “黄领衫”获奖感言
    2018上C语言程序设计(高级)作业- 第4次作业
    2018上C语言程序设计(高级)作业- 第3次作业
    2018上C语言程序设计(高级)作业- 第2次作业
  • 原文地址:https://www.cnblogs.com/handsomeye/p/5363893.html
Copyright © 2020-2023  润新知