zoukankan      html  css  js  c++  java
  • 单例设计模式

    单例模式(Singleton)

    简单来说,单例模式就是创建一个类,仅产生一个实例供外部访问。

    1.1 实现方案

    方案一:

     1 /**
     2  * 单例模式:方案一
     3  */
     4 public class Singleton {
     5 
     6     // 将构造方法私有化,防止以new的方式创建对象并且实例化
     7     private Singleton() {  }
     8 
     9     // 定义一个引用自身对象的属性,该属性为静态常量
    10     private static final Singleton instance = new Singleton();
    11 
    12     /**
    13      * 静态方法,返回该类的实例
    14      * @return
    15      */
    16     public static Singleton getInstance() {
    17         return instance;
    18     }
    19 }

           该方法较为简单,而且获取的实例是静态常量,因此不存在线程安全问题,完全摒弃了synchronized造成的性能问题。然而,当该类被加载时,就会创建静态常量对象,并且该对象会一直占有内存,直到该类卸载,因此有些情况下会造成内存问题。

           方案二:

     1 /**
     2  * 单例模式:方案二
     3  */
     4 public class Singleton {
     5 
     6     // 将构造方法私有化,防止以new的方式创建实例
     7     private Singleton() {  }
     8 
     9     // 定义一个自身类型的静态变量
    10     private static Singleton instance = null;
    11 
    12     /**
    13      * 静态方法,返回该类的实例
    14      * @return
    15      */
    16     public static Singleton getInstance() {
    17         // 判断该实例是否存在
    18         if (null == instance)
    19             instance = new Singleton();
    20         return instance;
    21     }
    22 }

           方案二仅仅是基于内存的节省对方案一的改造,但是如果在多线程环境下,有可能会产生多个实例对象,因此不是线程安全的。

           方案三:

     1 /**
     2 
     3  * 单例模式:方案三
     4 
     5  */
     6 
     7 public class Singleton {
     8 
     9     // 将构造方法私有化,防止以new的方式创建实例
    10 
    11     private Singleton() {  }
    12 
    13 
    14     // 定义一个自身类型的静态变量
    15 
    16     private static Singleton instance = null;
    17 
    18     /**
    19 
    20      * 静态方法,返回该类的实例
    21 
    22      * 方法添加同步锁,防止多线程访问产生多个实例
    23 
    24      * @return
    25 
    26      */
    27 
    28     public synchronized static Singleton getInstance() {
    29 
    30         // 判断该实例是否存在
    31 
    32         if (null == instance)
    33 
    34             instance = new Singleton();
    35 
    36         return instance;
    37     }
    38 }

           方案三在方案二的基础上为静态方法添加同步锁,以达到线程安全的要求。但是同步方法被频繁调用时,当然会存在效率问题。

           方案四:

     1 /**
     2 
     3  * 单例模式:方案四
     4 
     5  */
     6 
     7 public class Singleton {
     8     // 将构造方法私有化,防止以new的方式创建实例
     9 
    10     private Singleton() {  }
    11 
    12     // 定义一个自身类型的静态变量
    13 
    14     private static Singleton instance = null;
    15 
    16     /**
    17 
    18      * 静态方法,返回该类的实例
    19 
    20      * 方法内部添加同步块,不用每次调用方法都要获取同步锁
    21 
    22      * @return
    23 
    24      */
    25 
    26     public static Singleton getInstance() {
    27 
    28         // 判断该实例是否存在
    29 
    30         if (null == instance) {
    31 
    32             // 如果不存在,才获取同步锁,如果存在则直接返回对象
    33 
    34             synchronized(Singleton.class) {
    35 
    36                 if (null == instance) {
    37 
    38                     instance = new Singleton();
    39 
    40                 }
    41 
    42             }
    43 
    44         }
    45         return instance;
    46     }
    47 }

           方案四改进了方案三,保证只有在必要的情况下,即当对象没有创建的时候才获取同步锁,如果对象已经存在,则直接返回即可,实现了高效并且线程安全。

           方案四需要注意同步块中又进行了一次判断,原因是,如果当代码执行到第一次判断时,有可能另一个线程刚好创建了一个实例,因此,获取锁之后还要判断一次。

    即:-------------------------------------

    1.2 应用举例

    例如,在使用Jedis的时候,由于多线程下频繁使用,因此需要使用连接池来管理多个Jedis连接,而为了保证连接池只有一个,则需要采用单例模式,如果不用Spring来管理连接池,则需要使用单例模式:

     1 /**
     2 
     3  * Redis连接池工具
     4 
     5  */
     6 
     7 public class JedisPoolUtil {
     8 
     9     private static volatile JedisPool jedisPool = null;
    10 
    11     // 提供一个私有构造函数保证单例
    12 
    13     private JedisPoolUtil() { }
    14     /**
    15 
    16      * 获取一个<tt>JedisPool</tt>
    17 
    18      * @return jedisPool 一个单例的{JedisPool}
    19 
    20      */
    21 
    22     public static JedisPool getJedisPoolInstance() {
    23         if (null == jedisPool) {
    24             synchronized (JedisPool.class) {
    25                 if (null == jedisPool) {
    26                     JedisPoolConfig poolConfig = new JedisPoolConfig();
    27                     // poo2已经更改maxActive为maxTotal
    28                     poolConfig.setMaxTotal(32);
    29                     // pool2已经更改为maxWaitMillis
    30                     poolConfig.setMaxWaitMillis(100 * 1000);
    31                     jedisPool = new JedisPool(poolConfig, "0.0.0.0", 6379);
    32                 } // if end
    33             } // synchronized end
    34         } // if end
    35         return jedisPool;
    36     }
    37     public static void release(JedisPool jedisPool) {
    38         Jedis jedis = null;
    39         try {
    40             jedis = jedisPool.getResource();
    41         } finally {
    42             if (null != jedis)  jedis.close();
    43         }
    44     }
    45 }
  • 相关阅读:
    Java程序员之JS(一) 入门
    Java虚拟机(一)之开篇
    JDK/JRE/JVM区别与联系
    web开发视频(一)之环境准备
    Spring MVC 教程,快速入门,深入分析
    Java中“==和equals”的区别
    如何查看电脑最大支持多少GB内存
    win10 计算器calc命令打不开
    Win10图标显示不正常解决办法
    在系统右键菜单上添加程序
  • 原文地址:https://www.cnblogs.com/wang--lei/p/7191386.html
Copyright © 2011-2022 走看看