单例模式

最近在review代码的时候发现一个假单例模式, 从而想总结下单例模式。假单例模式代码如下:

 1 public class RuleContext {
 2 
 3     private static RuleContext ruleContext = new RuleContext();
 4 
 5     private ThreadLocal<List<Map<String, Object>>> ruleErrors = new ThreadLocal();
 6     
 7     public RuleContext() {
 8     }
 9 
10     public static RuleContext getInst() {
11         return ruleContext;
12     }
13 }

从代码中可以看出类的构造函数(第七行)是public类型,不能保证只有一个实例。

一、单例模式定义

从上面假单例代码中可以看出,单例模式保证一个类仅有一个实例,并且提供一个全局访问点。有以下几个特点:

      1、单例类只能有一个实例

      2、单例类必须自己实例化

      3、提供一个全局访问点

二、基本实现思路

   1、将类的构造方法定义为私有方法,这样其它地方就不能够通个构造方法来实例化该类对象,只有通过该类的静态方法来获得该类的实例

   2、在该类内部提供一个静态方法,当调用该方法时,判断类的实例是否为空,不为空则返回,为空则实例化对象

三、实现方式

   1、懒汉式, 线程不安全

    懒汉顾名思义:懒惰,当程序第一次访问单件模式实例时才进行创建。

 1 /**
 2  * <Description> <br>
 3  *
 4  * @author jy<br>
 5  * @version 1.0<br>
 6  * @taskId <br>
 7  * @CreateDate 2019年04月01日 <br>
 8  * @since R9.0<br>
 9  * @see com <br>
10  */
11 public class SingletonDemo {
12     // 利用静态变量来记录唯一实例
13     private static SingletonDemo singletonDemo;
14 
15     // 私有构造方法
16     private SingletonDemo() {
17 
18     }
19 
20     // 在该类内部提供一个静态方法获取实例
21     public static SingletonDemo getInstance() {
22         if (singletonDemo == null) {
23             singletonDemo = new SingletonDemo();
24         }
25         return singletonDemo;
26     }
27 }

 此实现方式为线程不安全,当两个线程同时访问getInstance方法时会初始化不同的实例,原因在于方法没有加synchronized锁,严格意义上此实现方式不为单例模式

   2、懒汉式,线程安全

   这种实现方式只需要在前一种方式中获取实例方法上加锁,效率低下,但是做到延迟加载,节省内存,代码如下

 1 public class SingletonDemo {
 2     // 利用静态变量来记录唯一实例
 3     private static SingletonDemo singletonDemo;
 4 
 5     // 私有构造方法
 6     private SingletonDemo() {
 7 
 8     }
 9 
10     // 在该类内部提供一个静态方法获取实例,加锁保证保证单例,效率会低下,每次都会
11     public static synchronized  SingletonDemo getInstance() {
12         if (singletonDemo == null) {
13             singletonDemo = new SingletonDemo();
14         }
15         return singletonDemo;
16     }
17 }

  3、饿汉式,线程安全

   饿汉:类加载时就初始化,基于 classloader 机制避免了多线程的同步问题,不用加锁,效率高,不能够延迟加载,浪费内存

 1 public class SingletonDemo2 {
 2     // 利用静态变量来记录唯一实例
 3     private static SingletonDemo2 singletonDemo = new SingletonDemo2();
 4 
 5     // 私有构造方法
 6     private SingletonDemo2() {
 7 
 8     }
 9 
10     // 在该类内部提供一个静态方法获取实例,
11     public static SingletonDemo2 getInstance() {
12         return singletonDemo;
13     }
14 }

4、双重检锁,线程安全

 1 public class SingletonDemo1 {
 2     /*
 3      * 利用静态变量来记录SingletonDemo1的唯一实例
 4      * volatile 关键字确保:当singleInstance变量被初始化成Singleton实例时,
 5      * 多个线程正确地处理singleInstance变量,实际上让cpu指令禁止指令重排
 6      */
 7     private volatile static SingletonDemo1 singleInstance;
 8 
 9     private SingletonDemo1() {
10 
11     }
12   
13     public static SingletonDemo1 getSingleInstance() {
14         if (singleInstance == null) {
15             synchronized (SingletonDemo1.class) {
16                 if (singleInstance == null) {
17                     singleInstance = new SingletonDemo1();
18                 }
19             }
20         }
21         return singleInstance;
22     }
23 }

5、静态内部类,线程安全

 1 public class SingletonDemo5 {
 2     /**
 3      * 静态内部类
 4      */
 5     private static class SingletonHolder {
 6         private static final SingletonDemo5 INSTANCE = new SingletonDemo5();
 7     }
 8 
 9     // 私有构造
10     private SingletonDemo5() {
11     }
12 
13     // 静态方法
14     public static final SingletonDemo5 getInstance() {
15         return SingletonHolder.INSTANCE;
16     }
17 }

6、枚举、线程安全

1 public enum Singleton6 {  
2     INSTANCE;  
3     public void whateverMethod() {  
4     }  
5 }

 

posted @ 2019-04-01 22:36  江洋小盗  阅读(132)  评论(0编辑  收藏  举报