Java并发 -- CSP模型
Go
- Go是一门号称从语言层面支持并发的编程语言,支持并发也是Go非常重要的特性之一
- Go支持协程,协程可以类比Java中的线程,解决并发问题的难点在于线程(协程)之间的协作
- Go提供了两种方案
- 支持协程之间以共享内存的方式通信,Go提供了管程和原子类来对协程进行同步控制,该方案与Java类似
- 支持协程之间以消息传递的方式通信,本质上是要避免共享,该方案是基于CSP模型实现的,Go推荐该方案
CSP模型
- CSP:Communicating Sequential Processes
- Do not communicate by sharing memory; instead, share memory by communicating.
累加器
1 | package main |
生产者-消费者模式
- 可以把Go实现的CSP模式类比成生产者-消费者模式,而channel类比成生产者-消费者模式中的阻塞队列
- Go中channel的容量可以为0,容量为0的channel被称为无缓冲的channel,容量大于0的channel被称为有缓冲的channel
- 无缓冲的channel类似于Java中提供的SynchronousQueue,主要用途是在两个协程之间做数据交换
- Go中的channel是语言层面支持的,使用左向箭头
<-
完成向channel发送数据和读取数据的任务 - Go中的channel是支持双向传输的,即一个协程既可以通过它发送数据,也可以通过它接收数据
- Go中的双向channel可以变成一个单向channel
- calc中创建了一个双向channel,但是返回的是一个只能接收数据的单向channel
- 所以在主协程中,只能通过该channel接收数据,而不能通过它发送数据
1 | // 创建一个容量为4的channel |
Actor模式
- Go实现的CSP模式和Actor模式都是通过消息传递的方式来避免共享,主要有以下三个区别
- Actor模型中没有channel,Actor模型中的Mailbox与channel非常类似,看起来都是FIFO队列,但本质区别很大
- Actor模型
- Mailbox对程序员是透明的,Mailbox明确归属于某一个特定的Actor,是Actor模型的内部机制
- Actor之间可以直接通信,不需要通信媒介
- CSP模型
- channel对于程序员来说是可见的
- channel是通信媒介,传递的消息都直接发送到channel中
- Actor模型
- Actor模型中发送消息是非阻塞的,而CSP模型中是阻塞的
- Go实现的CSP模型,channel是一个阻塞队列
- 当阻塞队列已满的时候,向channel发送数据,会导致发送消息的协程阻塞
- Actor模型理论上不保证消息百分比送达,而Go实现的CSP模型中,是能保证消息百分百送达的(代价:可能导致死锁)
1 | func main() { |
小结
- CSP模型是Tony Hoare在1978年提出的,该模型一直都在发展,其理论远比Go实现的复杂得多
- Tony Hoare在并发领域还有另一项重要成就,即霍尔管程模型,这是Java解决并发问题的理论基础
- Java可以借助第三方类库JCSP来支持CSP模型,相比Go的实现,JCSP更接近理论模型
- JCSP并没有经过广泛的生产环境检验,因此不推荐在生产环境使用
参考资料
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.