auto commit
This commit is contained in:
parent
621cbe8103
commit
fa8d126354
|
@ -58,11 +58,11 @@
|
|||
|
||||
### 实现
|
||||
|
||||
**(一)懒汉式-线程不安全**
|
||||
(一)懒汉式-线程不安全
|
||||
|
||||
以下实现中,私有静态变量 uniqueInstance 被延迟化实例化,这样做的好处是,如果没有用到该类,那么就不会实例化 uniqueInstance,从而节约资源。
|
||||
|
||||
这个实现在多线程环境下是不安全的,如果多个线程能够同时进入 if (uniqueInstance == null) ,并且此时 uniqueInstance 为 null,那么多个线程会执行 uniqueInstance = new Singleton(); 语句,这将导致实例化多次 uniqueInstance。
|
||||
这个实现在多线程环境下是不安全的,如果多个线程能够同时进入 if (uniqueInstance == null) ,并且此时 uniqueInstance 为 null,那么多个线程会执行 uniqueInstance = new Singleton(); 语句,这将导致多次实例化 uniqueInstance。
|
||||
|
||||
```java
|
||||
public class Singleton {
|
||||
|
@ -81,7 +81,7 @@ public class Singleton {
|
|||
}
|
||||
```
|
||||
|
||||
**(二)懒汉式-线程安全**
|
||||
(二)懒汉式-线程安全
|
||||
|
||||
只需要对 getUniqueInstance() 方法加锁,那么在一个时间点只能有一个线程能够进入该方法,从而避免了对 uniqueInstance 进行多次实例化的问题。
|
||||
|
||||
|
@ -96,7 +96,7 @@ public static synchronized Singleton getUniqueInstance() {
|
|||
}
|
||||
```
|
||||
|
||||
**(三)饿汉式-线程安全**
|
||||
(三)饿汉式-线程安全
|
||||
|
||||
线程不安全问题主要是由于 uniqueInstance 被实例化了多次,如果 uniqueInstance 采用直接实例化的话,就不会被实例化多次,也就不会产生线程不安全问题。但是直接实例化的方式也丢失了延迟实例化带来的节约资源的优势。
|
||||
|
||||
|
@ -104,7 +104,7 @@ public static synchronized Singleton getUniqueInstance() {
|
|||
private static Singleton uniqueInstance = new Singleton();
|
||||
```
|
||||
|
||||
**(四)双重校验锁-线程安全**
|
||||
(四)双重校验锁-线程安全
|
||||
|
||||
uniqueInstance 只需要被实例化一次,之后就可以直接使用了。加锁操作只需要对实例化那部分的代码进行。也就是说,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
|
||||
|
||||
|
@ -143,17 +143,17 @@ if (uniqueInstance == null) {
|
|||
|
||||
uniqueInstance 采用 volatile 关键字修饰也是很有必要的。uniqueInstance = new Singleton(); 这段代码其实是分为三步执行。
|
||||
|
||||
1. 分配内存空间。
|
||||
2. 初始化对象。
|
||||
3. 将 uniqueInstance 指向分配的内存地址。
|
||||
1. 分配内存空间
|
||||
2. 初始化对象
|
||||
3. 将 uniqueInstance 指向分配的内存地址
|
||||
|
||||
但是由于 JVM 具有指令重排的特性,有可能执行顺序变为了 1>3>2,这在单线程情况下自然是没有问题。但如果是多线程下,有可能获得是一个还没有被初始化的实例,以致于程序出错。
|
||||
|
||||
使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。
|
||||
|
||||
**(五)枚举实现**
|
||||
(五)枚举实现
|
||||
|
||||
这是单例模式的最佳实践,它实现简单,并且在复杂的序列化或者反射攻击的时候,能够防止实例化多次。
|
||||
这是单例模式的最佳实践,它实现简单,并且在面对复杂的序列化或者反射攻击的时候,能够防止实例化多次。
|
||||
|
||||
```java
|
||||
public enum Singleton {
|
||||
|
@ -283,7 +283,7 @@ public class Client {
|
|||
|
||||
在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
|
||||
|
||||
下图中,Factory 有一个 doSomethind() 方法,这个方法需要用到一组产品对象,这组产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
|
||||
下图中,Factory 有一个 doSomethind() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
|
||||
|
||||
<div align="center"> <img src="../pics//1818e141-8700-4026-99f7-900a545875f5.png"/> </div><br>
|
||||
|
||||
|
@ -341,15 +341,15 @@ public class ConcreteFactory2 extends Factory {
|
|||
|
||||
### 类图
|
||||
|
||||
<div align="center"> <img src="../pics//8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png"/> </div><br>
|
||||
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
|
||||
|
||||
抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
|
||||
|
||||
抽象工厂模式用到了工厂模式来创建单一对象,AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂模式的定义。
|
||||
抽象工厂模式用到了工厂方法模式来创建单一对象,AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂方法模式的定义。
|
||||
|
||||
至于创建对象的家族这一概念是在 Client 体现,Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client 需要同时创建出这两个对象。
|
||||
|
||||
从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂模式使用了继承。
|
||||
从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂方法模式使用了继承。
|
||||
|
||||
<div align="center"> <img src="../pics//8668a3e1-c9c7-4fcb-98b2-a96a5d841579.png"/> </div><br>
|
||||
|
||||
### 代码实现
|
||||
|
||||
|
@ -584,7 +584,7 @@ abc
|
|||
|
||||
### 意图
|
||||
|
||||
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
|
||||
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
|
||||
|
||||
### 类图
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user