zoukankan      html  css  js  c++  java
  • JAVA实现单例模式

    JAVA实现单例模式主要有:懒汉、饿汉、双重检验锁、静态内部类和枚举几种方式。

    一、懒汉,线程不安全

    public class Singleton {
        private static Singleton instance;
        private Singleton (){}
        public static Singleton getInstance() {
         if (instance == null) {
             instance = new Singleton();
         }
         return instance;
        }
    }
    

     这种方式之所以线程不安全是因为当多个线程同时使用getInstance()方法时,可能产生多个实例。

    二、懒汉,线程安全

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

    加上synchronized关键字后,保证了线程安全,但是任何时候只能有一个线程调用getInstance()方法,所以并不高效。

    三、饿汉

    public class Singleton{
        //类加载时就初始化
        private static final Singleton instance = new Singleton();
        
        private Singleton(){}
        public static Singleton getInstance(){
            return instance;
        }
    }
    

     这种方式使得类在装载时就创建了实例。

    四、双重检验锁

    public class Singleton {
        private volatile static Singleton instance; //声明成 volatile
        private Singleton (){}
        public static Singleton getSingleton() {
            if (instance == null) {                         
                synchronized (Singleton.class) {
                    if (instance == null) {       
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
       
    }
    

     这里有两点要注意,一是两次检验instance==null,因为可能有多个线程同时进入外面的if,如果没有内部if检查,会创建多个实例。二是volatile关键字。因为instance=new Singleton()分三步进行:

    1) 给instance分配内存;

    2)调用Singleton构造函数初始化成员变量;

    3)将instance对象指向内存空间。

    由于JVM编译器中存在指令排序的优化,也就是说2)和3)的顺序是不能保证的。设想一下,如果执行顺序是1,3,2,在执行完3之后,然后被线程二占用,这时instance已经是非null,线程二直接返回instance,这样在使用时就会报错。

    volatile的作用在于禁止指令重排序优化。

    五、静态内部类

    public class Singleton {  
        private static class SingletonHolder {  
            private static final Singleton INSTANCE = new Singleton();  
        }  
        private Singleton (){}  
        public static final Singleton getInstance() {  
            return SingletonHolder.INSTANCE; 
        }  
    }
    

     这也是一种”懒汉”的方式,把实例化推迟到使用getInstance()方法之后。

    六、枚举

    public enum EasySingleton{
        INSTANCE;
    }
    

     可见枚举类型是最简单的一种方法。

  • 相关阅读:
    C++ 动态库导出函数名“乱码”及解决
    ASP.NET 4.5 Bundle组件(捆绑、缩小静态文件)
    MVC4 + WebAPI + EasyUI + Knockout-授权代码维护
    关于Grunt可视化的尝试
    Object-c学习之路三(@class与#import的区别)
    2.1 以指定的次序返回查询结果
    进程序名得到进程ID和句柄与进程的公司名(使用快照和GetPeFileCompany和VerQueryValueW等函数)
    在资源里面画出你的界面
    VS2008下WinRar源码生成dll和 lib总结
    进程占用百分百CPU不卡(从未试过,当别的程序运行的时候,当前程序还会运行吗?)
  • 原文地址:https://www.cnblogs.com/lumouren009/p/4255880.html
Copyright © 2011-2022 走看看