zoukankan      html  css  js  c++  java
  • 设计模式(3)---单例模式

    单例模式 Singleton (创建型模式)

     

    1.定义

    单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。

     

    2.结构图

     

    3.代码

    懒汉式

     1 /*
     2  * 懒汉式
     3  * 实现了延迟创建和保证了线程安全
     4  */
     5 public class Singleton {
     6 
     7     private static Singleton instance = null ;
     8     
     9     private Singleton() {
    10         
    11     }
    12     
    13     public static synchronized Singleton getInstance(){
    14         if (instance == null){
    15             instance = new Singleton() ;
    16         }
    17         return instance ;
    18     }
    19 
    20 }

     

    双重检查加锁

    synchronized对整个方法加锁是没必要的,只要保证实例化对象的那段代码不被多线程同时访问就行了,当两个线程同时访问这个方法时,假设这时对象还没有被实例化,他们都可以通过第一重instance==null的判断,然后由于lock机制,这两个线程只有一个能进入,如果没有第二重的判断,则第一个线程创建了实例后,第二个线程还是可以继续再创建新的实例。

     1 /*
     2  * 双重检查加锁
     3  * 
     4  */
     5 public class Singleton {
     6 
     7     private volatile static Singleton instance = null ;
     8     
     9     private Singleton() {
    10         
    11     }
    12     
    13     public static  Singleton getInstance(){
    14         if (instance == null){
    15             synchronized(Singleton.class){
    16                 if (instance == null){
    17                     instance = new Singleton() ;
    18                 }
    19             }    
    20         }
    21         return instance ;
    22     }
    23 
    24 }


    Instance 采用 volatile 关键字修饰也是很有必要的。

    Instance = new Singleton(); 这段代码其实是分为三步执行。

    1. 分配内存空间。
    2. 初始化对象。
    3. 将 Instance 指向分配的内存地址。

    但是由于 JVM 具有指令重排的特性,有可能执行顺序变为了 1>3>2,这在单线程情况下自然是没有问题。但如果是多线程就有可能 B 线程获得是一个还没有被初始化的对象以致于程序出错。

    所以使用 volatile 修饰的目的是禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。



    采用静态内部类的形式
    Java中静态内部类可以访问其外部类的成员属性和方法,同时,静态内部类只有当被调用的时候才开始首次被加载,利用此特性,可以实现懒汉式,在静态内部类中静态初始化外部类的单一实例即可。
    既是线程安全的,同时又提升了性能
     1 /*
     2  * 懒汉形式改进版   采用了静态内部类
     3  * 
     4  */
     5 public class Singleton {
     6 
     7     private Singleton() {
     8         
     9     }
    10     private static class LazyHolder{
    11         private static final Singleton instance = new Singleton();
    12     }
    13     
    14     public static  Singleton getInstance(){
    15         return LazyHolder.instance ;
    16     }
    17 
    18 }

     

    或者

     1 /**
     2  * 请求内存队列
     3  * @author Administrator
     4  *
     5  */
     6 public class RequestQueue {
     7     
     8     /**
     9      * 单例有很多种方式去实现:我采取绝对线程安全的一种方式
    10      * 
    11      * 静态内部类的方式,去初始化单例
    12      * 
    13      * @author Administrator
    14      *
    15      */
    16     private static class Singleton {
    17         
    18         private static RequestQueue instance;
    19         
    20         static {
    21             instance = new RequestQueue();
    22         }
    23         
    24         public static RequestQueue getInstance() {
    25             return instance;
    26         }
    27         
    28     }
    29     
    30     /**
    31      * jvm的机制去保证多线程并发安全
    32      * 
    33      * 内部类的初始化,一定只会发生一次,不管多少个线程并发去初始化
    34      * 
    35      * @return
    36      */
    37     public static RequestQueue getInstance() {
    38         return Singleton.getInstance();
    39     }
    40     
    41 
    42     
    43 }
    饿汉形式

     1 /*
     2  * 饿汉形式
     3  * 
     4  */
     5 public class Singleton {
     6 
     7     private static final Singleton instance = new Singleton() ;
     8     
     9     private Singleton() {
    10         
    11     }
    12     
    13     public static  Singleton getInstance(){
    14         return instance ;
    15     }
    16 
    17 }

     

     

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

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

     

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

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

  • 相关阅读:
    说说Cookie和Session
    说说SQL Server的数据类型
    Java访问权限控制
    数据库-- 触发器
    关于jni编译32位、64位动态库(Android.mk和Application.mk文件)
    Android中的 init.rc文件简介
    Android系统属性简介
    Android Support 包知识
    Android窗口机制分析与UI管理系统
    Android界面架构(Activity,PhoneWiondow,DecorView)简介
  • 原文地址:https://www.cnblogs.com/mengchunchen/p/5727627.html
Copyright © 2011-2022 走看看