单例模式(Singleton Pattern)——独一无二的对象

来源:互联网 发布:ge矩阵 编辑:程序博客网 时间:2024/05/16 15:57

前言

​ 有一些对象其实我们只需要一个,比如说,线程池、缓存、对话框、处理偏好设置和注册表的对象、日志对象,充当但印记、显卡等设备的驱动程序的对象,事实上,这个对象只能有一个实例。如果制造出多个实例,就会大致许多问题的产生,例如:程序的异常行为、资源使用过量,或者不一致的结果。

​ 怎么样样才能保证一个类只有一个实例并且能够全局访问到呢?全局变量?那么你必须在程序一开始就创建好对象。万一这个对象非常耗费资源,二程序在这次的执行过程中又一直没有用到它,不就形成浪费了吗?这时候,单例模式就闪亮登场。

概述

定义

单例模式(singleton pattern),head first设计模式中又名单件模式。确保一个类只有一个实例,并提供一个全局访问点。

注意

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

类图

这里写图片描述

  1. uniqueInstance变量持有唯一的单件实例
  2. getInstance()方法是静态公共方法,可以和全局变量一样访问,但是单例可以通过这个方法延迟实例化
  3. 单例模式的类也可以是一般的类,具有一般的属性和方法

设计模式的实现

从书上和其它博客了解到,单例模式有6种实现,感觉很精妙。

1. 懒汉式,线程不安全

//不支持多线程。没有加锁 synchronized。---再多线程的环境中不算单例public class Singleto{   private static Singleton uniqueInstance;      private Singleton (){}      public static Singleton getInstance() {      if (uniqueInstance == null) {          uniqueInstance = new Singleton();      }      return uniqueInstance;      } }

2. 懒汉式,线程安全

// 能够在多线程中很好的工作,但是,因为加了synchronized锁,效率很低。public class Singleton {      private static Singleton uniqueInstance;      private Singleton (){}      public static synchronized Singleton getInstance() {      if (uniqueInstance == null) {          uniqueInstance = new Singleton();      }      return uniqueInstance;      }  } 

3. 饿汉式,线程安全,但是不是延迟加载

// 相对于方法二,这种方式没有加锁,效率会高一些。但是容易产生垃圾对象(?暂时还不懂?)// 类加载时就初始化,不是延迟加载,其实就是一个全局静态变量,很浪费内存。// 它基于 classloder 机制避免了多线程的同步问题。(不懂)  后续要了解classloader!!!public class Singleton {      private static Singleton uniqueInstance = new Singleton();      private Singleton (){}      public static Singleton getInstance() {      return uniqueInstance;      }  }  

4. 双检锁/双重校验锁(DCL,即double-checked locking),线程安全

// 这种方式采用双检锁机制,安全且在多线程情况下能保持高性能。public class Singleton(){  private static Singleton uniqueInstance;  private Singleton(){}  public static Singleton getInstance(){    if(uniqueInstance == null){      sychronized(Singleton.class){        if(uniqueInstance == null){          uniqueInstance = new Singleton();        }      }    }    return uniqueInstance;  }}// 针对上述中的 sychronized(Singgle.class) 这里做一个说明://static synchronized方法,static方法可以直接类名加方法名调用,方法中无法使用this,所以它锁的不是this,而是类的Class对象,所以,static synchronized方法也相当于全局锁,相当于锁住了代码段。// 以下摘自 http://blog.csdn.net/shenshibaoma/article/details/53009505// 用以记录// synchronized锁住的是代码还是对象。答案是:synchronized锁住的是括号里的对象,而不是代码。对于非static的synchronized方法,锁的就是对象本身也就是this。// 当synchronized锁住一个对象后,别的线程如果也想拿到这个对象的锁,就必须等待这个线程执行完成释放锁,才能再次给对象加锁,这样才达到线程同步的目的。即使两个不同的代码段,都要锁同一个对象,那么这两个代码段也不能在多线程环境下同时运行。// 所以我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步。这叫减小锁的粒度,使代码更大程度的并发。原因是基于以上的思想,锁的代码段太长了,别的线程是不是要等很久,等的花儿都谢了。

5. 登记式/静态内部类,线程安全

// 这种方式,达到双检锁方式一样的效果,实现更简单。同样采用classloader机制,来保证初始化 instance 时只有一个线程。但是与第三种方式不同的是,这里只有getInstance被调用后,才会实例化对象。实现了延迟加载。public class Singleton {      private static class SingletonHolder {      private static final Singleton UNIQUEINSTANCE = new Singleton();      }      private Singleton (){}      public static final Singleton getInstance() {      return SingletonHolder.UNIQUEINSTANCE;      }  }   

6. 枚举,线程安全——一脸懵逼的代码

// 这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。// ??不懂。。。public enum Singleton {      UNIQUEINSTANCE;      public void whateverMethod() {      }  }  

总结

​ 哇~~~突然感觉java基础太差了,最后的设计模式的实现,好多没懂。虽然,单例模式,是我接触的第一个设计模式,但是,说实话4、5、6三种,以前真没见过。涨姿势了,虽然我还没懂呢。等我懂了,我再好好补充补充。QAQ~

阅读全文
0 0
原创粉丝点击