每天一模式——单例模式

来源:互联网 发布:女朋友活好体验 知乎 编辑:程序博客网 时间:2024/06/06 01:04

一、单例模式是为了控制类只有一个实例对象,通常在以下两种情况需要考虑使用单例模式:

1、业务逻辑的需求

2、性能的考虑

二、单例模式的机构图:


三、单例模式的几种实现形式:

1、形式一

public class Singleton2 {private static Singleton2 instance;private Singleton2() {}public  static Singleton2 getInstance(){if(instance==null){instance = new Singleton2();}return instance;}}
2、形式二

public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance(){return instance;}}
注意:对于第一种形式来说,其最大的问题是不适合于多线程模式。

3、形式三——改进形式一,使其在多线程模式下能正常运行:

public class Singleton2 {private static Singleton2 instance;private Singleton2() {}public synchronized  static Singleton2 getInstance(){if(instance==null){instance = new Singleton2();}return instance;}}
加上关键字synchronized后,确实能保证线程的安全,但是存在的问题是,验证影响效率,因为同步整个方法,会使得所有的线程需要顺序执行,不能并发执行。

4、形式四——修正形式三,提高效率:

public class Singleton2 {private volatile static Singleton2 instance;private Singleton2() {}public  static Singleton2 getInstance(){if(instance==null){synchronized(Singleton2.class){if(instance==null){instance = new Singleton2();}}}return instance;}}
这段代码的核心是:双重检查并加锁。双重检查的作用在于不需要同步整个方法,可以并发执行程序,并且在加锁的情况下可以保证线程的安全。这个地方还需要注意的关键字是volatile,但是该关键字仅仅能保证读取的是最新指值,而无法保证原子性操作,更不能保证同步。因为在JVM中每个线程有自己的内存空间,正常情况下,该内存区间会保存堆中变量的一个副本,然后完成操作后写回堆中,使用volatile关键能保证不使用线程的缓存,而直接读取堆中的值。从而保证每次读取的值是最新的值,但是有可能同时两个线程读取了该变量,然后再依次修改该变量。