• (非原创)JAVA学习(二)单例模式


    原文链接:http://www.ibm.com/developerworks/cn/java/j-lo-Singleton/index.html

    http://blog.csdn.net/jason0539/article/details/23297037

    单例模式

    考虑这样一个应用,读取配置文件的内容。很多应用项目,都有与应用相关的配置文件,这些配置文件很多是由项目开发人员自定义的,在里面定义一些应用重要的参数数据。当然,在实际的项目中,这种配置文件多数采用 xml 格式,也有采用 properties 格式的,我们这里假设创建了一个名为 AppConfig 的类,它专门用来读取配置文件内的信息。客户端通过 new 一个 AppConfig 的实例来得到一个操作配置文件内容的对象。如果在系统运行中,有很多地方都需要使用配置文件的内容,也就是说很多地方都需要创建 AppConfig 对象的实例。换句话说,在系统运行期间,系统中会存在很多个 AppConfig 的实例对象,这里读者有没有发现有什么问题存在?当然有问题了,试想一下,每一个 AppConfig 实例对象里面都封装着配置文件的内容,系统中有多个 AppConfig 实例对象,也就是说系统中会同时存在多份配置文件的内容,这样会严重浪费内存资源。如果配置文件内容越多,对于系统资源的浪费程度就越大。事实上,对于 AppConfig 这样的类,在运行期间只需要一个实例对象就足够了。

    从专业化来说,单例模式是一种对象创建模式,它用于产生一个对象的具体实例,它可以确保系统中一个类只产生一个实例。Java 里面实现的单例是一个虚拟机的范围,因为装载类的功能是虚拟机的,所以一个虚拟机在通过自己的 ClassLoad 装载实现单例类的时候就会创建一个类的实例。在 Java 语言中,这样的行为能带来两大好处:

    1. 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;

    2. 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。

    因此对于系统的关键组件和被频繁使用的对象,使用单例模式可以有效地改善系统的性能。单例模式的核心在于通过一个接口返回唯一的对象实例。首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类的实例的创建工作,然后由这个类来提供外部可以访问这个类实例的方法

    单例模式有以下特点:
      1、单例类只能有一个实例。
      2、单例类必须自己创建自己的唯一实例。
      3、单例类必须给所有其他对象提供这一实例。

    一、懒汉式单例

     

    1. //懒汉式单例类.在第一次调用的时候实例化自己   
    2. public class Singleton {  
    3.     private Singleton() {}  
    4.     private static Singleton single=null;  
    5.     //静态工厂方法   
    6.     public static Singleton getInstance() {  
    7.          if (single == null) {    
    8.              single = new Singleton();  
    9.          }    
    10.         return single;  
    11.     }  
    12. }  
    Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。

    (事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)

    但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全,如果你第一次接触单例模式,对线程安全不是很了解,可以先跳过下面这三小条,去看饿汉式单例,等看完后面再回头考虑线程安全的问题:

    1、在getInstance方法上加同步

    1. public static synchronized Singleton getInstance() {  
    2.          if (single == null) {    
    3.              single = new Singleton();  
    4.          }    
    5.         return single;  

    2、双重检查锁定

      

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

    3、静态内部类


     

    1. public class Singleton {    
    2.     private static class LazyHolder {    
    3.        private static final Singleton INSTANCE = new Singleton();    
    4.     }    
    5.     private Singleton (){}    
    6.     public static final Singleton getInstance() {    
    7.        return LazyHolder.INSTANCE;    
    8.     }    
    9. }    

    这种比上面1、2都好一些,既实现了线程安全,又避免了同步带来的性能影响。

     

    二、饿汉式单例


     

    1. //饿汉式单例类.在类初始化时,已经自行实例化   
    2. public class Singleton1 {  
    3.     private Singleton1() {}  
    4.     private static final Singleton1 single = new Singleton1();  
    5.     //静态工厂方法   
    6.     public static Singleton1 getInstance() {  
    7.         return single;  
    8.     }  
    9. }  
    饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

     

    总结:

    单例模式是用来实现在整个程序中只有一个实例的设计模式方法。本文通过从最基础的单例模式开始讲解,逐渐进入到延迟加载、锁机制、内部、静态类等单例模式实现方法,让读者可以学习单例模式的具体应用。设计模式的核心理念是活学活用,所以不会有什么规则是固定不变的规则,需要读者在实际应用过程中不断尝试、不断创新,力求代码间接明了、易于扩展。

  • 相关阅读:
    Java NIO3:缓冲区Buffer
    Java NIO2:NIO概述
    Mybatis学习总结(六)——高级映射(一对一,一对多,多对多)
    Java NIO1:浅谈I/O模型
    Java多线程(三)—— synchronized关键字详解
    Java IO(五)——字符流进阶及BufferedWriter、BufferedReader
    Java IO(四)——字符流
    mysql 实现树形的遍历
    Java IO(三)——字节流
    使用 SVN Hook 实现服务器端代码自动更新
  • 原文地址:https://www.cnblogs.com/hexie/p/4883620.html
Copyright © 2020-2023  润新知