Java设计模式之单例模式

前言

单例模式在实际项目中起着非常重要的作用,笔者将从以下几点来讲解。

1.单例模式的概念

2.单例模式的类图

3.单例模式的几种表达形式

单例模式的概念

        单例模式保证某一个具体的类只有一个实例,并且只有自己才能实例化,同时向整个系统开放这个实例。

单例模式的类图

 

 1 public class Singleton {
 2 
 3     private static final Singleton instance = new Singleton();
 4 
 5     private Singleton () {
 6 
 7     }
 8 
 9     public static Singleton getInstance() {
10         return instance;
11     }
12 }
Singleton类称为单例类,同时构造函数是以private修饰,防止外部通过new 关键字自行获得实例,同时提供一个获取实例的共有成员函数。因此可以确保在整个系统中,Singleton有且仅有一个实例。

单例模式的几种表达形式

 单例模式在表达形式上可以分为这么几类

1.饿汉式

2.懒汉式

3.双检锁

4.静态内部类的方式

5.静态代码块的方式

6.枚举的方式

下面重点来介绍一下前三种方式。

饿汉式

       饿汉式,既然叫饿汉式,指的就是无论在系统中是否用到该实例,这个实例都会在当类被加载器加载时产生。上述的例子就是饿汉式的通用写法。这种写法不会引起资源的竞争,同时会不会存在线程安全的问题呢?

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

第3行,当某线程A执行到new Singleton()时,没有实例化完成,线程A切换至线程B,因此内存中会出现两份实例?这两份实例指向不同的内存地址?这不就出现了线程的不安全的问题吗?

懒汉式

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

懒汉式和饿汉式刚好相反,懒汉式只有在应用中开始调用该实例时,才回去实例化,同时该实例保存在内存中。不过这种写法基本上在实际项目中不会去采用,因为存在线程安全的问题,当线程A执行到第11行时,线程切换至线程B,线程A和B同时执行new Singleton,因此内存中会出现多份实例的引用,这已经和单例模式的初衷相违背。

双检锁

双检锁的写法是为了解决懒汉式写法的线程不安全。具体代码如下所示:

 1 public class Singleton {
 2 
 3     private static Singleton instance = null;
 4 
 5     private static Object monitor = new Object();
 6 
 7     private Singleton () {
 8 
 9     }
10 
11     public static Singleton getInstance() {
12 
13         if(instance == null) {
14 
15             synchronized (Singleton.class) {
16 
17                 if(instance == null) {
18                     instance = new Singleton();
19                 }
20             }
21 
22         }
23         return instance;
24     }
25 }

 不过也并不是线程绝对的安全。为了保证在高并发下线程安全,需要在instance之前加上关键字volatile,从而保证在多线程之间切换时的可见性,同时防止指令重排序。

单例模式的优点

1. 因为在整个应用中,有且只有一个实例,减少了内存的开支,避免了同一对象频繁的创建和销毁,所以大大节省了资源的消耗。

2.唯一的实例一旦创建,便会保存在内存中,减少系统的开销,尤其是给对象读取较多的资源,比如读取配置文件,一次读取就可以永久的保存在内存中

3.单例模式保证了对资源的多重占用,比如对一个文件的操作,我们采取线程安全的单例模式进行操作。 

单例模式的缺点

1.单例模式是一个单例类,因此没有抽象接口,因此会存在扩展性差的缺点,业务逻辑发生了变化,除了修改类之外没有别的办法,这显然和设计原则中的对修改关闭对扩展开放的原则。

原文地址:https://www.cnblogs.com/sunshine798798/p/9473883.html