Java 单例(Singleton)模式

一、什么是单例模式:

单例模式是一种确保了一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。被实例化的类称为单例类。

二、单例模式的特点:

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

注意:虽然单例模式和单例类限定了只能有一个实例,但是作为单例模式的推广,可以推广到任意且有限多个实例的情况,这时候被称为多例模式和多例类。

三、单例模式的结构:

  1. 一个单例类只有一个实例。
  2. 单例类的实例持有对自己的引用。

四、单例模式的实例化:

Java中单例模式有着自己的特点,具体表现在单例类的实例化上:

饿汉式单例类(静态常量)

 1 /**
 2  * 饿汉式(静态常量)
 3  *
 4  * @author ZhouDX
 5  * @since 2019/3/4 22:12:28
 6  */
 7 public class HungerSingleton {
 8     private static final HungerSingleton SINGLETON= new HungerSingleton();
 9 
10     /**
11      * 私有的默认构造函数
12      */
13     private HungerSingleton() {
14     }
15 
16     /**
17      * 静态工厂方法
18      */
19     public static HungerSingleton getInstance() {
20         return SINGLETON;
21     }
22 }

Java中最简单的单例类,类的单例被声明为静态变量,在类加载时,调用类的私有构造函数,静态变量被实例化。

特点:

  1.类的构造函数私有,避免了外界利用构造函数创建任意多的实例。

  2.且由于构造函数私有,类不能被继承。

  3.只能通过静态方法getInstance()来获取类的实例对象。

优点:

  类装载的时候就完成实例化。避免了线程同步问题。

缺点:

  在类装载的时候就完成实例化,没有达到延迟加载的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

  饿汉式单例类(静态代码块):

 1 /**
 2  * 饿汉式单例类(静态代码块)
 3  *
 4  * @author ZhouDX
 5  * @since 2019/3/13 22:45:24
 6  */
 7 public class HungerSington_StaticCode {
 8     private static HungerSington_StaticCode singleton;
 9 
10     /**
11      * 静态代码块
12      */
13     static {
14         singleton= new HungerSington_StaticCode();
15     }
16 
17     /**
18      * 私有构造函数
19      */
20     private HungerSington_StaticCode() {
21     }
22 
23     /**
24      * 获取单例类实例的唯一接口
25      *
26      * @return 单例类
27      */
28     public static HungerSington_StaticCode getInstance() {
29         return singleton;
30     }
31 }

  特点:

  将单例类放在静态代码块中,也是类在加载时执行静态代码块中的代码,完成类的实例化,优缺点同静态常量。

汉懒式单例类(线程不安全):

 1 /**
 2  * 懒汉式(线程不安全)[不可用]
 3  *
 4  * @author ZhouDX
 5  * @since 2019/3/13 22:52:24
 6  */
 7 public class LazySingleton_ThreadUnsafe {
 8     private static LazySingleton_ThreadUnsafe singleton;
 9 
10     /**
11      * 获取单例类实例
12      *
13      * @return 单例类实例
14      */
15     public static LazySingleton_ThreadUnsafe getInstance() {
16         if (null == singleton) {
17             singleton = new LazySingleton_ThreadUnsafe();
18         }
19 
20         return singleton;
21     }
22 }

  特点:

  1.达到了延迟加载的目的,只有在单例类第一次被引用时将自己实例化。

  2.在单线程下使用。

  缺点:  

  在多线程的环境中,多个线程同时进入if (null == singleton) {},还未执行singleton = new LazySingleton_ThreadUnsafe()时,另一个线程也恰好进入这里,就会造成单例类多个实例,线程不安全,不可以再多线程的环境下使用。

  懒汉式(线程安全,同步方法)

 1 /**
 2  * 懒汉式(线程安全,同步方法)
 3  *
 4  * @author ZhouDX
 5  * @since 2019/3/4 22:23:02
 6  */
 7 public class LazySingleton {
 8     private static LazySingleton lazySingleton = null;
 9 
10     /**
11      * 构造函数
12      */
13     private LazySingleton() {
14     }
15 
16     /**
17      * 静态工厂方法,返回懒汉式实力类的唯一实例
18      *
19      * @return
20      */
21     public static synchronized LazySingleton getInstance() {
22         if (lazySingleton == null) {
23             return lazySingleton = new LazySingleton();
24         }
25         return lazySingleton;
26     }
27 }

  特点:

  使用了synchronized对静态工厂类方法进行了同步,安全处理多线程的问题。

  缺点:

  每个线程执行getInstance()方法都要进行同步,大大降低了执行的效率。且getInstance()只需要实例化一次就可以。

  懒汉式(线程不安全,同步代码块)

 1 /**
 2  * 懒汉式(线程安全,同步代码块)
 3  *
 4  * @author ZhouDX
 5  * @since 2019/3/13 23:12:08
 6  */
 7 public class LaSingleton_ThreadUnsafe {
 8     private static LaSingleton_ThreadUnsafe singleton;
 9 
10     /**
11      * 静态构造方法
12      */
13     private LaSingleton_ThreadUnsafe() {
14     }
15 
16     /**
17      * 获取单例类实例
18      *
19      * @return 单例类实例
20      */
21     public static LaSingleton_ThreadUnsafe getInstance() {
22         if (null == singleton) {
23             synchronized (LaSingleton_ThreadUnsafe.class) {
24                 singleton = new LaSingleton_ThreadUnsafe();
25             }
26         }
27         return singleton;
28     }
29 }

  特点:

  同步产生实例的代码块。

  缺点:

  假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。

  懒汉式(双重检查):

 1 /**
 2  * 懒汉式(双重检查):
 3  *
 4  * @author ZhouDX
 5  * @since 2019/3/13 23:24:27
 6  */
 7 public class LazySingleton_DoubleCheck {
 8     private static volatile LazySingleton_DoubleCheck singleton;
 9 
10     /**
11      * 静态构造方法
12      */
13     private LazySingleton_DoubleCheck() {
14     }
15 
16     /**
17      * 获取单例类实例
18      *
19      * @return 单例类实例
20      */
21     public static LazySingleton_DoubleCheck getInstance() {
22         if (null == singleton) {
23             synchronized (LazySingleton_DoubleCheck.class) {
24                 singleton = new LazySingleton_DoubleCheck();
25             }
26         }
27         return singleton;
28     }
29 }

  特点:

  1.进行了两次if (singleton == null)检查,保证了线程安全。

  2.实例化代码只执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。

  优点:

  程安全;延迟加载;效率较高。

  静态内部类:

 1 /**
 2  * 静态内部类
 3  *
 4  * @author ZhouDX
 5  * @since 2019/3/13 23:28:58
 6  */
 7 public class Singleton_StaticInnerClass {
 8     /**
 9      * 私有构造方法
10      */
11     private Singleton_StaticInnerClass() {
12     }
13 
14     /**
15      * 静态内部类
16      */
17     private static class SingletonInstance {
18         private static final Singleton_StaticInnerClass SINGLETON = new Singleton_StaticInnerClass();
19     }
20 
21     /**
22      * 获取单例类实例
23      *
24      * @return 单例类实例
25      */
26     private static Singleton_StaticInnerClass getInstance() {
27         return SingletonInstance.SINGLETON;
28     }
29 }

  特点:

  类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

  优点:

  避免了线程不安全,延迟加载,效率高。

  枚举:

 1 /**
 2  * 枚举
 3  *
 4  * @author ZhouDX
 5  * @since 2019/3/13 23:33:43
 6  */
 7 public enum Singleton_Enum {
 8     SINGLETON;
 9 
10     public void whateverMethod() {
11     }
12 }

  特点:

  系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。

  优点:

  当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new,可能会给其他开发人员造成困扰,特别是看不到源码的时候。

懒汉式单例类与饿汉式单例类的比较:

  1. 饿汉式单例类在自己被加载时将自己实例化,即便加载器是静态的,依旧在加载时实例化自己;懒汉式单例类在第一次被引用时将自己实例化,如果加载器是静态的,懒汉式单例类被加载时不会将自己实例化。
  2. 从资源利用角度讲,懒汉式单例类的资源利用效率高点;从速度和反应时间来讲,饿汉式的好点。

 

posted @ 2019-03-04 22:41  派大小兴  阅读(291)  评论(0编辑  收藏  举报