5858
5959### 实现
6060
61- ** (一)懒汉式-线程不安全**
61+ (一)懒汉式-线程不安全
6262
6363以下实现中,私有静态变量 uniqueInstance 被延迟化实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance,从而节约资源。
6464
65- 这个实现在多线程环境下是不安全的,如果多个线程能够同时进入 if (uniqueInstance == null) ,并且此时 uniqueInstance 为 null,那么多个线程会执行 uniqueInstance = new Singleton(); 语句,这将导致实例化多次 uniqueInstance。
65+ 这个实现在多线程环境下是不安全的,如果多个线程能够同时进入 if (uniqueInstance == null) ,并且此时 uniqueInstance 为 null,那么多个线程会执行 uniqueInstance = new Singleton(); 语句,这将导致多次实例化 uniqueInstance。
6666
6767``` java
6868public class Singleton {
@@ -81,7 +81,7 @@ public class Singleton {
8181}
8282```
8383
84- ** (二)懒汉式-线程安全**
84+ (二)懒汉式-线程安全
8585
8686只需要对 getUniqueInstance() 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了对 uniqueInstance 进行多次实例化的问题。
8787
@@ -96,15 +96,15 @@ public static synchronized Singleton getUniqueInstance() {
9696}
9797```
9898
99- ** (三)饿汉式-线程安全**
99+ (三)饿汉式-线程安全
100100
101101线程不安全问题主要是由于 uniqueInstance 被实例化了多次,如果 uniqueInstance 采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全问题。但是直接实例化的方式也丢失了延迟实例化带来的节约资源的优势。
102102
103103``` java
104104private static Singleton uniqueInstance = new Singleton ();
105105```
106106
107- ** (四)双重校验锁-线程安全**
107+ (四)双重校验锁-线程安全
108108
109109uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行。也就是说,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
110110
@@ -143,17 +143,17 @@ if (uniqueInstance == null) {
143143
144144uniqueInstance 采用 volatile 关键字修饰也是很有必要的。uniqueInstance = new Singleton(); 这段代码其实是分为三步执行。
145145
146- 1 . 分配内存空间。
147- 2 . 初始化对象。
148- 3 . 将 uniqueInstance 指向分配的内存地址。
146+ 1 . 分配内存空间
147+ 2 . 初始化对象
148+ 3 . 将 uniqueInstance 指向分配的内存地址
149149
150150但是由于 JVM 具有指令重排的特性,有可能执行顺序变为了 1>3>2,这在单线程情况下自然是没有问题。但如果是多线程下,有可能获得是一个还没有被初始化的实例,以致于程序出错。
151151
152152使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。
153153
154- ** (五)枚举实现**
154+ (五)枚举实现
155155
156- 这是单例模式的最佳实践,它实现简单,并且在复杂的序列化或者反射攻击的时候 ,能够防止实例化多次。
156+ 这是单例模式的最佳实践,它实现简单,并且在面对复杂的序列化或者反射攻击的时候 ,能够防止实例化多次。
157157
158158``` java
159159public enum Singleton {
@@ -164,7 +164,7 @@ public enum Singleton {
164164考虑以下单例模式的实现,该 Singleton 在每次序列化的时候都会创建一个新的实例,为了保证只创建一个实例,必须声明所有字段都是 transient,并且提供一个 readResolve() 方法。
165165
166166``` java
167- public class Singleton implements Serializable {
167+ public class Singleton implements Serializable {
168168
169169 private static Singleton uniqueInstance;
170170
@@ -283,7 +283,7 @@ public class Client {
283283
284284在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
285285
286- 下图中,Factory 有一个 doSomethind() 方法,这个方法需要用到一组产品对象,这组产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
286+ 下图中,Factory 有一个 doSomethind() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
287287
288288<div align =" center " > <img src =" ../pics//1818e141-8700-4026-99f7-900a545875f5.png " /> </div ><br >
289289
@@ -341,15 +341,15 @@ public class ConcreteFactory2 extends Factory {
341341
342342### 类图
343343
344- <div align =" center " > <img src =" ../pics//8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png " /> </div ><br >
345-
346- 抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
344+ 抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
347345
348- 抽象工厂模式用到了工厂模式来创建单一对象 ,AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂模式的定义 。
346+ 抽象工厂模式用到了工厂方法模式来创建单一对象 ,AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂方法模式的定义 。
349347
350348至于创建对象的家族这一概念是在 Client 体现,Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client 需要同时创建出这两个对象。
351349
352- 从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂模式使用了继承。
350+ 从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂方法模式使用了继承。
351+
352+ <div align =" center " > <img src =" ../pics//8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png " /> </div ><br >
353353
354354### 代码实现
355355
584584
585585### 意图
586586
587- 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求 ,直到有一个对象处理它为止。
587+ 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求 ,直到有一个对象处理它为止。
588588
589589### 类图
590590
0 commit comments