auto commit

This commit is contained in:
CyC2018 2018-06-21 17:32:32 +08:00
parent 621cbe8103
commit fa8d126354

View File

@ -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 {
@ -164,7 +164,7 @@ public enum Singleton {
考虑以下单例模式的实现,该 Singleton 在每次序列化的时候都会创建一个新的实例,为了保证只创建一个实例,必须声明所有字段都是 transient并且提供一个 readResolve() 方法。
```java
public class Singleton implements Serializable{
public class Singleton implements Serializable {
private static Singleton uniqueInstance;
@ -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
### 意图
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
### 类图