zoukankan      html  css  js  c++  java
  • Java单例类的简单实现

        对于java新手来说,单例类给我的印象挺深,之前一道web后台笔试题就是写单例类。*.*可惜当时不了解。

        在大部分时候,我们将类的构造器定义成public访问权限,允许任何类自由创建该类的对象。但在某些时候,允许其他类自由创建该类的对象没有任何意义,还可能造成系统性能下降(因为频繁地创建对象、回收对象带来的系统开销问题)。例如,系统可能只有一个窗口管理器、一个假脱机打印设备或一个数据库引擎访问点,此时如果在系统中为这些类创建多个对象就没有太大的实际意义。因此,在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。

        Java单例类有以下特点:

      1、单例类始终只能创建一个实例。
      2、单例类必须自己创建自己的唯一实例。
      3、单例类必须给所有其他对象提供这一实例。

        实现要求:

      1、类的构造器使用private修饰,隐藏该类的所有构造器;

      2、根据良好封装原则,提供public方法作为该类的访问点,用于创建该类的对象,且该方法必须使用static修饰;

      3、类必须缓存已经创建的对象,故需要一个static修饰的成员变量。

        先看一个单例类的经典实现:

    class Singleton 
    {    
        private static Singleton instance;
        private Singleton() {}
        public static Singleton getInstance()
        {
            if(instance == null)
                instance = new Singleton();
            return instance;
        }
    }
    public class SingletonTest
    {
        public static void main(String[] args)
        {
            Singleton s1 = Singleton.getInstance();
            Singleton s2 = Singleton.getInstance();
            System.out.println(s1 == s2);
        }    
    }

       通过上面的getInstance()方法提供的自定义控制,保证Singleton类只能产生一个实例。(这也是封装的优势:不允许自由访问类的Field和实现细节,而是通过方法来提供访问接口)所以在SingletonTest类的main方法中,看到两次产生的Singleton对象实际上是同一个对象,程序输出“true”。

          关于单例类的三种实现方式:饿汉式单例类、懒汉式单例类、登记式单例类(暂时还不懂*.*)

      1.饿汉式单例类:立即创建实例

    class Singleton1
    {
        //已经自行实例化 
        private static final Singleton1 instance = new Singleton1();
    
        private Singleton1() {}
        public static Singleton1 getInstance()
        {
            return instance;
        }
    }

      2.懒汉式单例类:在第一次调用时实例化

    class Singleton2 
    {
        //注意,这里没有final    
        private static Singleton2 instance=null;
    
        private Singleton2() {} 
        public static Singleton2 getInstance() 
        {
             if (instance == null) 
                 instance = new Singleton2(); 
            return instance;
        }
    }

      但上面这段程序在多线程环境中是不能保证单个实例的。例如下表所示多线程可能情况:

    时间点 线程1 线程2 instance值
    1 进入getInstance()方法   null
    2   进入getInstance()方法 null
    3 执行if(uniqueInstance == null)判断   null
    4   执行if(uniqueInstance == null)判断 null
    5 执行instance = new Singleton()   Singleton1
    6   执行instance = new Singleton() Singleton2
    7 执行return instance;   Singleton1
    8   执行return instance; Singleton2

      因此,便有了多线程安全的懒汉式单例类实现:

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

       因为通过给getInstance()方法增加synchronized关键字,也就是给getInstance()方法线程加锁,迫使每次只能有一个线程进入这个方法。但加锁的同步方法可能造成程序执行效率大幅度下降,因为对 Singleton2类来说,只有在第一次执行getInstance()方法时,才真正的需要对方法进行加锁同步,因为一旦第一次设置好instance 变量后,就不再需要同步这个方法了。之后每次调用这个方法,同步反而成了一种累赘。

      3.用"双重检查加锁",在getInstance()方法中减少使用同步:

    public class Singleton 
    {
    // volatile关键字确保当instance变量被初始化成Singleton实例时,多个线程正确地处理instance变量 private volatile static Singleton instance; private Singleton() {} public static Singleton getInstance()
    {
    if (instance == null) {// 检查实例,如是不存在就进行同步代码区 synchronized (Singleton.class) {// 对其进行加锁,防止两个线程同时进入同步代码区 if (instance == null) {// 双重检查,非常重要,如果两个同时访问的线程,当第一线程访问完同步代码区后,生成一个实例;当第二个已进入getInstance方法等待的线程进入同步代码区时,也会产生一个新的实例 instance = new Singleton(); } } } return instance; } }

      参考:

      ITeye.com,java单例模式(Singleton pattern) : http://www.iteye.com/topic/652617

         

  • 相关阅读:
    【转载】SAP_ECC6.0_EHP4或SAP_ECC6.0_EHP5_基于Windows_Server_2008R2_和SQL_server_2008下的安装
    使用delphi 开发多层应用(二十四)KbmMW 的消息方式和创建WIB节点
    使用delphi 开发多层应用(二十三)KbmMW 的WIB
    实现KbmMw web server 支持https
    KbmMW 服务器架构简介
    Devexpress VCL Build v2014 vol 14.1.1 beta发布
    使用delphi 开发多层应用(二十二)使用kbmMW 的认证管理器
    KbmMW 4.50.00 测试版发布
    Basic4android v3.80 beta 发布
    KbmMW 认证管理器说明(转载)
  • 原文地址:https://www.cnblogs.com/chenbjin/p/3619003.html
Copyright © 2011-2022 走看看