zoukankan      html  css  js  c++  java
  • Java设计模式-单例模式

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

      Java中单例模式是一种常见的设计模式,单例模式的写法有多种,这里主要只介绍:懒汉式单例、饿汉式单例

      单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例

      选择单例模式就是为了避免不一致状态,同时也可减少资源消耗

    一、懒汉式单例

     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()方法访问。

      但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,要实现线程安全,有以下三种方式,都是对getInstance这个方法改造,保证了懒汉式单例的线程安全

      1、在getInstance方法上加同步

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

      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 package com.singleton;
     2 
     3 //懒汉式单例类,在第一次调用的时候实例化自己
     4 //但是懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例
     5 //为什么会出现线程安全问题呢?
     6 //当多个线程去调用 Class.getInstance 时,在线程1自己的内存空间中,是没有实例的,所以会新创建一个,线程2又去调用instance,又创建一个
     7 
     8 //可以有三种改进方法:1.在getInstance方法上加同步  2.双重检查锁定  3.静态内部类(这种比较好)
     9 public class SingletonLazy {
    10     private SingletonLazy() {
    11     }
    12 
    13     // 在类被初始化的时候,不会为这个成员变量赋值(懒),必须要等到调用 getInstance 才会去创建实例
    14     /*private static SingletonLazy singleton = null;  (这里不能加final,初始为null,加了final 之后,指向不能改变,就一直是null了)
    15 
    16     // 静态工厂方法
    17     public static SingletonLazy getInstance() {
    18         if (singleton == null) {
    19             singleton = new SingletonLazy();
    20         }
    21         return singleton;
    22     }*/
    23 
    24     //静态内部类的方式,在SingletonLazy类被初始化的时候,没有成员变量可以去初始化
    25     //当调用 getInstance 的时候,通过类加载器的方式 加载LazyHolder,同时加载LazyHolder 的单例实例
    26     //因为类加载器的方式 是线程安全的,所以 这个也是线程安全的
    27     private static class LazyHolder {
    28         private static final SingletonLazy INSTANCE = new SingletonLazy();  //(加上final,创建后不会被修改)
    29     }
    30 
    31     public static final SingletonLazy getInstance() {
    32         return LazyHolder.INSTANCE;
    33     }
    34 }
    35     

    二、饿汉式单例

     1 //饿汉式单例,在类初始化的时候,已经自行实例化
     2 //在真正调用这个类的时候,才会完成这个类的初始化,为静态成员变量赋初始值,
     3 //保证getInstance 的时候,单例已经存在了
     4 //为什么这样是线程安全的呢?
     5 //猜想:类的加载初始化只会加载一次,SingletonHungry也只会被创建一次,(加上final,创建后不会被修改) 当多个线程去调用Class.getInstance方法时,getInstance做的不是创建,而是把我早就创建好的直接给你,所以拿到的是同一个实例(一个引用变量)
     6 public class SingletonHungry {
     7     private static final SingletonHungry singleton = new SingletonHungry();
     8     
     9     private SingletonHungry(){};
    10     
    11     public static SingletonHungry getInstance() {
    12         return singleton;
    13     }
    14 }

      饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

    三、饿汉式和懒汉式的区别:

      饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了,

      而懒汉比较懒,只有当调用getInstance的时候,才会去初始化这个单例

      另外从以下两点再区分以下这两种方式:

       1、线程安全:

      饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题,

      懒汉式本身是非线程安全的,为了实现线程安全有几种写法,分别是上面的1、2、3,这三种实现在资源加载和性能方面有些区别。



      2、资源加载和性能:

      饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,

      而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。

      至于1、2、3这三种实现又有些区别,

        第1种,在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的,

        第2种,在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗

        第3种,利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗,所以一般我倾向于使用这一种

     

     

  • 相关阅读:
    Unix命令大全
    vs2008 与 IE8出现的兼容性问题
    Java 创建文件、文件夹以及临时文件
    如何修改Wamp中mysql默认空密码
    PAT 乙级真题 1003.数素数
    Tags support in htmlText flash as3
    DelphiXE4 FireMonkey 试玩记录,开发IOS应用 还是移植
    10 Great iphone App Review sites to Promote your Apps!
    HTML tags in textfield
    Delphi XE4 IOS 开发, "No eligible applications were found“
  • 原文地址:https://www.cnblogs.com/xuzekun/p/7466322.html
Copyright © 2011-2022 走看看