设计模式-单例模式(Singleton Pattren)(饿汉模式和懒汉模式)

单例模式(Singleton Pattren):确保一个类在整个应用中只有一个实例,并提供一个全局访问点。

实现要点:

1. 私有化构造方法

2. 类的实例在类初始化的时候创建

3. 提供一个类方法,返回值为类的实例,其他类调用该方法获取到该类的实例

 

1. 常规实现(线程不安全,不考虑多线程):

 1 public class Singleton1 {
 2     private static Singleton1 instance;
 3 
 4     private Singleton1() {
 5 
 6     }
 7 
 8     public static Singleton1 getInstance() {
 9         if (instance == null) {
10             instance = new Singleton1();
11         }
12         return instance;
13     }
14 }

2. 线程安全懒加载实现(懒汉式):

 1 public class Singleton2 {
 2     private volatile static Singleton2 instance;
 4 
 5     private Singleton2() {
 6     }
 7 
 8     public Singleton2 getInstance() {
 9         if (instance == null) {
10             synchronized (Singleton2.class) {
11                 if (instance == null) {
12                     instance = new Singleton2();
13                 }
14             }
15         }
16         return instance;
17     }
18 }

3. 线程安全快速加载实现(饿汉式):

 1 public class Singleton3 {
 2     private static Singleton3 instance = new Singleton3();
 3 
 4     private Singleton3() {
 5     }
 6 
 7     public static Singleton3 getInstance() {
 8         return instance;
 9     }
10 }

三种实现方法中:

第一种,假如在单线程模式下,是可以的,不会出现多个实例的情况,但是在多线程的模式下是不安全的,可能会创建多个实例。

第二种,在方法内部进行了加锁操作,同时使用 volatile 修饰 instance,防止 Java 指令重排,确保当变量 instance 被初始化成 Singleton2 实例时,多个线程正确的处理 instance 变量。该写法只有在使用的时候才会初始化对象,可以提高性能。

第三种,比较简单的写法,在类被加载的时候就初始化了对象,所以在调用的时候直接返回这个变量就可以了,线程安全由 JVM 来确保,因为 JVM 加载的时候是单线程的。不存在线程不安全的问题,但是该对象在类加载进 JVM 的时候就初始化了,会占用资源。

 

一种更好的写法,弥补饿汉式初始化以后不使用对象占用资源的问题,弥补懒汉式初始化过程中使用 synchronized 影响性能的问题 

 1 public class Singleton4 {
 2 
 3     private Singleton4() {
 4     }
 5 
 6     private static class Holder {
 7         private static Singleton4 instance = new Singleton4();
 8     }
 9 
10     public static Singleton4 getInstance() {
11         return Holder.instance;
12     }
13 }

由于静态单例对象没有作为Singleton的成员变量直接实例化,因此类加载时不会实例化Singleton,第一次调用getInstance()时将加载内部类HolderClass,在该内部类中定义了一个static类型的变量instance,此时会首先初始化这个成员变量,由Java虚拟机来保证其线程安全性,确保该成员变量只能初始化一次。由于getInstance()方法没有任何线程锁定,因此其性能不会造成任何影响。

 知识点: 可以写出三种单例模式,参考:《Effictive Java》单例模式的实现

参考:http://blog.csdn.net/lovelion/article/details/7420888

posted @ 2017-03-05 21:32  熠然  阅读(582)  评论(0编辑  收藏  举报