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

      单例模式就是是一个类仅可以创建一个对象,在java中实现主要有两种方式:饿汉式和懒汉式。

      先看两种方式共有的部分,因为是单例,所以构造方法必须是私有的private,而且必须提供一个对外界开放的获取对象的方法,该方法内部控制返回唯一的一个对象实例:

    public class Singleton {
    
        //构造方法私有,阻断外界直接创建对象的方法
        private Singleton() {}
        
        //提供一个获取唯一对象实例的方法
        public static Singleton getInstance(){
            //...
        }
        
    }

      以上是不管什么方式的实现,都得遵循的一些规定,下面就介绍懒汉式和饿汉式:

      饿汉式是单例类感觉自己很饥饿(将实例对象想象为吃的),不管有没有别的类跟我要实例类,我都要自己先生成一个,像下面的实现: 

    public class Singleton {
    
        //构造方法私有,阻断外界直接创建对象的方法
        private Singleton() {}
        
        //内部持有一个类初始化时唯一创建的一个类实例对象
        private static Singleton singleton = new Singleton();
        
        //提供一个获取唯一对象实例的方法
        public static Singleton getInstance(){
            return singleton;
        }
        
    }

      饿汉式的有点在于编码逻辑简单好理解,无线程安全问题;缺点嘛,自然就是当我仅仅是想用Singleton类其他方法,他还是创建了一个对我现在来说没用的实例对象,当系统中这种饿汉式的单例类多起来的时候,无疑是一种资源浪费,这个问题正好懒汉式可以解决。

      懒汉式,就是自己首先持有一个空的单例类的实例,但是不会类一加载就创建实例,只有当别人第一次要我的实例对象我才给他创建,懒嘛,要是没人要我就不创建了:

    public class Singleton {
    
        //构造方法私有,阻断外界直接创建对象的方法
        private Singleton() {}
        
        //内部持有一个单例类的引用
        private static Singleton singleton = null;
        
        //提供一个获取唯一对象实例的方法
        public static Singleton getInstance(){
            if(singleton==null){
                singleton = new Singleton();
            }
            return singleton;
        }
        
    }

      饿汉式的有点不用说了,就是解决了懒汉式的缺点;但是他的缺点就是多线程环境下,不尽人意啊,比如两个线程同时都是第一次去获取Singleton类的实例的时候,又同时执行到if(singleton==null)这一行,两个线程就会同时进入if语句执行体中去,可能先后执行了singleton = new Singleton();这就违反了单例模式的概念,所以还得想个办法解决这个问题。

      线程安全的饿汉式:(其实只要将if语句上加上线程锁,就可以避免两个线程一起跑到这个地方来了)

    public class Singleton {
    
        //构造方法私有,阻断外界直接创建对象的方法
        private Singleton() {}
        
        //内部持有一个单例类的引用
        private static Singleton singleton = null;
        
        //提供一个获取唯一对象实例的方法
        public static Singleton getInstance(){
            synchronized (Singleton.class) {
                if(singleton==null){
                    singleton = new Singleton();
                }
            }
            return singleton;
        }
        
    }

      踏哒~,解决了,但是!你发现了么?这样的话,每次别人想获取sinleton实例的时候都得等待别的线程释放锁,自己再加锁,自己再释放锁,而这些锁的操作又是那么消耗时间,能不能再优化一下。想一想,是不是第一次访问完了,只要sington对象实例,不为空,直接返回就是了,没有现成问题啊,应该这样:

    public class Singleton {
    
        //构造方法私有,阻断外界直接创建对象的方法
        private Singleton() {}
        
        //内部持有一个单例类的引用
        private static Singleton singleton = null;
        
        //提供一个获取唯一对象实例的方法
        public static Singleton getInstance(){
            if(singleton==null){
                synchronized (Singleton.class) {
                    if(singleton==null){
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
        
    }

      完美!线程安全的懒汉式,既解决了资源浪费问题,又兼顾了线程安全问题。

      不过还有个更巧妙地方法,这个就涉及到内部类的只是,当一个类加载的时候,其内部类并不加载,而是只要第一次用到内部类的时候内部类才会加载,而且如果这个内部类是static内部类,也就是说加载了这个类一次,以后就直接获取他就可以了,详细参见另一篇博客:http://www.cnblogs.com/WreckBear/p/5812942.html

    public class Singleton {
    
        //构造方法私有,阻断外界直接创建对象的方法
        private Singleton() {}
        
        /*
         * 搭建一个内部静态类,外部类加载的时候,内部类并不会加载,
         * 只有当内部类被访问的时候才会被加载、初始化,加载之后就会一直保存在内存中
         */
        public static class Get{
            public static Singleton singleton = new Singleton();
        }
        
    }

      在Main中获取:

    public class Main {
    
        public static void main(String[] args) {
            Singleton singleton = Singleton.Get.singleton;
        }
    }

      这种方法显得更加优雅一点,至此,结束!

  • 相关阅读:
    dotnet 新项目格式与对应框架预定义的宏
    dotnet 线程静态字段
    dotnet 线程静态字段
    dotnet 通过 WMI 拿到显卡信息
    dotnet 通过 WMI 拿到显卡信息
    dotnet 通过 WMI 获取指定进程的输入命令行
    dotnet 通过 WMI 获取指定进程的输入命令行
    dotnet 通过 WMI 获取系统信息
    dotnet 通过 WMI 获取系统信息
    PHP show_source() 函数
  • 原文地址:https://www.cnblogs.com/WreckBear/p/5813003.html
Copyright © 2011-2022 走看看