• 设计模式(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的时候,才回去初始化这个单例。

     

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

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

  • 相关阅读:
    Android平台架构及特性
    MySQL 数据库性能优化之索引优化
    排序自己总结
    存储过程中“ 警告: 聚合或其他 SET 操作消除了 Null 值” 导致错误的解决
    存储过程的output及return的区别
    如果ssh端口转发时候g没有效果解决方案
    sql语句显示复选内容, indication 为复选框的累计value(整数),显示所有的
    kprfakesu.c Linux su密码欺骗 源码
    Unix/Linux上的后门技术和防范
    iis7应用程序池经常自动停止如何解决?
  • 原文地址:https://www.cnblogs.com/mengchunchen/p/5727627.html
Copyright © 2020-2023  润新知