笔记 图解Java多线程设计模式

  1. 1.Single Threaded Execution模式
  2. 2.immutable模式
  3. 3.guarded suspension模式
  4. 4.balking 模式
  5. 5.producer-consumer模式
  6. 6.Read-Write Lock模式
  7. 7.Thread-Per-Message模式
  8. 8.workder thread模式 (线程池)
  9. 9.future模式
  10. 10.Two-Phase Termination
  11. 11.Thread Specific Storage
  12. 12.Active Object

图解Java多线程设计模式的笔记。


1.Single Threaded Execution模式

这一章,讲述了synchronized的用法。

synchronized的目的主要是保护一个数据集的统一性。

1)数据集应该是一个数据类。

1
2
3
4
5
6
7
8
9
10
public class Gate {
    
    //...
    
    class Data {//共享资源(数据)
        private int counter = 0;
        private String name = "Nobody";
        private String address = "Nowhere";
    }
}

原因:时刻让程序员明白,synchronized要保护的是什么。倘若出现数据类的数据的公开方法,就应该使用synchronized进行保护。

2)存在第三方来管理共享资源?

如果是自己使用Data这种缓存的话,就不得不自身考虑数据块的完整性。那么,如果将这种缓存问题交给第三方,是不是就没有这种担忧呢?

不严谨的搜索,这种是可能的。Ehcache、Redis、数据库等均可以,但是需要考虑传输效率以及安全性。

PS : long和double操作不是原子。(嫌弃的表情)


2.immutable模式

immutable模式讲述数据类不可变。

不变性的重要特点就是与上下文(context)隔绝,也就是处于隔离状态。这是数据类的状态之一。

immutable的数据与没有状态的行为在一起,也就可以看作是一个“原子操作”。例子可参考Java 8 lambda的传值。

The JLS mentions why in §15.27.2:

The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems.

To lower risk of bugs, they decided to ensure captured variables are never mutated.

PS : 从另一个角度看,Single Threaded Execution模式和immutable模式其分别代表了,引用传递和值传递


3.guarded suspension模式

实质解决类中方法间的通讯。

常见是使用wait()和 notifyAll()。是使用Java底层的机制。


4.balking 模式

和guarded suspension模式类似,区别在于其选择的方案。

1
2
3
4
5
6
    while (守护条件) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }

条件不符时候:

guarded suspension使用wait等待,需要notify

balking则终止操作/进行其他操作,不需要notify

思考:balking模式的利用?

balking思想关键在于,立刻返回。在异步和同步,异步是立刻返回一个引用,而同步则是返回真实的值。

再深一步思考,异步的实质就是将“同步”的过程拆开,分为两个步骤。平常,正常的过程是:“计算+返回”,而异步则是先返回,后计算。


5.producer-consumer模式

生产者消费者模式, 重点在于容器,通过容器管理生产和消费。

优点:

  1. 读写分离,读可多个。
  2. 多线程问题外置。

这种操作颇有IOC的风格,通过第三方解耦。这个问题主要在于,两个类之间存在多线程的关联,然而多线程的操作分开则不好写,也不利于维护,所以放在第三方更为好。


6.Read-Write Lock模式

多线程问题,常常就是资源的问题。

对于某个资源来说,若个类之间的关系究竟是如何?

  1. 竞争关系
  2. 共生关系(producer-consumer, 周瑜打黄盖)

由于是容器管理,所以其各个操作必然存在锁。

竞争关系则存在,若干情况

  1. 同方法之间的竞争
  2. 不同方法之间的竞争

共生关系仅仅有

  1. 不同类之间的关系,而且这个关系不是竞争,生产者和消费者的例子则是wait和notify


7.Thread-Per-Message模式

主要讲述的是异步的思想。主线程不操作,而是新建新城,委托其完成。


8.workder thread模式 (线程池)

Thread-Per-Message的修改版本,增加了容器概念,并在容器中增加若干个固有线程。


9.future模式

future模式是barking模式+Thread-Per-Message模式。

Thread-Per-Message模式中,主线程和新建线程之间的关系是:启动和被动。这种关系是单向的,不友好的。

而future模式下,主线程和新线程是具有数据交互的。也就是说,在新建线程执行完任务后会返回结果给主线程。

思考:如何解决future返回的结果导致的堵塞

需要一个容器,对结果进行储存,并在主线程进行统一的处理。


10.Two-Phase Termination

讲述为多线程增加生命周期,这里主要是讲述,为一群线程。也就是说,其实可以在ExecutorService等类中,直接增加生命周期。

这一生命周期主要为了达到同步。


11.Thread Specific Storage

这个模式和线程池类似,区别在于,线程池的线程是持续存在,而"Thread Specific Storage"则是一次性/专属。


12.Active Object

是一种异步的解决方案。其重点就是,中间用容器进行actor(线程)的通讯。

task-based、actor-based、CSP

CSP(Communicating Sequential Process) 应该是基于任务的模式,其特点就是没有固定角色,任务来了,就执行。从这点可以看,所有必要信息和行为都再任务当中。

而基于角色,则是角色拥有行为,通过发送/收取容器的信息,从而达到角色之间的通信。而发送/获取的这些行为存在于容器中,信息则是角色拥有。

参考:并发编程:Actors模型和CSP模型