博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
十分钟读懂:Java并发——CSP模型
阅读量:5342 次
发布时间:2019-06-15

本文共 3058 字,大约阅读时间需要 10 分钟。

Go

  1. Go是一门号称从语言层面支持并发的编程语言,支持并发也是Go非常重要的特性之一
  2. Go支持协程,协程可以类比Java中的线程,解决并发问题的难点在于线程(协程)之间的协作
  3. Go提供了两种方案
    • 支持协程之间以共享内存的方式通信,Go提供了管程和原子类来对协程进行同步控制,该方案与Java类似
    • 支持协程之间以消息传递的方式通信,本质上是要避免共享,该方案是基于CSP模型实现的,Go推荐该方案

CSP模型

  1. CSP:Communicating Sequential Processes
  2. Do not communicate by sharing memory; instead, share memory by communicating.

累加器

package mainimport (    "fmt"    "time")func main() {    singleCoroutine()    multiCoroutine()}// 单协程,只能用到CPU的一个核func singleCoroutine() {    var result, i uint64    start := time.Now()    for i = 1; i <= 10000000000; i++ {        result += i    }    elapsed := time.Since(start)    fmt.Println(elapsed, result) // 4.330357206s 13106511857580896768}// 多协程func multiCoroutine() {    var result uint64    start := time.Now()    ch1 := calc(1, 2500000000)    ch2 := calc(2500000001, 5000000000)    ch3 := calc(5000000001, 7500000000)    ch4 := calc(7500000001, 10000000000)    // 主协程需要与子协程通信,Go中协程之间的通信推荐使用channel    result = <-ch1 + <-ch2 + <-ch3 + <-ch4    // ch1只能读取数据,如果通过ch1写入数据,编译时会报错    // ch1 <- 7 // invalid operation: ch1 <- 7 (send to receive-only type <-chan uint64)    elapsed := time.Since(start)    fmt.Println(elapsed, result) // 1.830920702s 13106511857580896768}// 返回一个只能接收数据的channel// 方法创建的子协程会把计算结果发送到这个channel,而主协程会通过channel把计算结果取出来func calc(from uint64, to uint64) <-chan uint64 {    // channel用于协程间的通信,这是一个无缓冲的channel    channel := make(chan uint64)    go func() {        result := from        for i := from + 1; i <= to; i++ {            result += i        }        // 将结果写入channel        channel <- result    }()    // 返回用于通信的channel    return channel}

生产者-消费者模式

  1. 可以把Go实现的CSP模式类比成生产者-消费者模式,而channel类比成生产者-消费者模式中的阻塞队列
  2. Go中channel的容量可以为0,容量为0的channel被称为无缓冲的channel,容量大于0的channel被称为有缓冲的channel
  3. 无缓冲的channel类似于Java中提供的SynchronousQueue,主要用途是在两个协程之间做数据交换
  4. Go中的channel是语言层面支持的,使用左向箭头<-完成向channel发送数据和读取数据的任务
  5. Go中的channel是支持双向传输的,即一个协程既可以通过它发送数据,也可以通过它接收数据
  6. Go中的双向channel可以变成一个单向channel
    • calc中创建了一个双向channel,但是返回的是一个只能接收数据的单向channel
    • 所以在主协程中,只能通过该channel接收数据,而不能通过它发送数据
// 创建一个容量为4的channelchannel := make(chan int, 4)// 创建4个协程,作为生产者for i := 0; i < 4; i++ {    go func() {        channel <- 7    }()}// 创建4个协程,作为消费者for i := 0; i < 4; i++ {    go func() {        o := <-channel        fmt.Println("received : ", o)    }()}

Actor模式

  1. Go实现的CSP模式和Actor模式都是通过消息传递的方式来避免共享,主要有以下三个区别
  2. Actor模型中没有channel,Actor模型中的Mailbox与channel非常类似,看起来都是FIFO队列,但本质区别很大
  • Actor模型
    • Mailbox对程序员是透明的,Mailbox明确归属于某一个特定的Actor,是Actor模型的内部机制
    • Actor之间可以直接通信,不需要通信媒介
  • CSP模型
    • channel对于程序员来说是可见的
    • channel是通信媒介,传递的消息都直接发送到channel中
  1. Actor模型中发送消息是非阻塞的,而CSP模型中是阻塞的
  • Go实现的CSP模型,channel是一个阻塞队列
  • 当阻塞队列已满的时候,向channel发送数据,会导致发送消息的协程阻塞
  1. Actor模型理论上不保证消息百分比送达,而Go实现的CSP模型中,是能保证消息百分百送达的(代价:可能导致死锁)
func main() {    // 无缓冲的channel    channel := make(chan int)    // fatal error: all goroutines are asleep - deadlock!    // 主协程会阻塞在此处,发生死锁    <-channel}

小结

  1. CSP模型是Tony Hoare在1978年提出的,该模型一直都在发展,其理论远比Go实现的复杂得多
    • Tony Hoare在并发领域还有另一项重要成就,即霍尔管程模型,这是Java解决并发问题的理论基础
  2. Java可以借助第三方类库JCSP来支持CSP模型,相比Go的实现,JCSP更接近理论模型
    • JCSP并没有经过广泛的生产环境检验,因此不推荐在生产环境使用

写在最后

 

转载于:https://www.cnblogs.com/Java-no-1/p/11172825.html

你可能感兴趣的文章
fastjson将java list转为json字符串
查看>>
pandas关联mysql并读写数据库
查看>>
sas format 输出
查看>>
白话TCP三次握手
查看>>
JS工具库之Lodash
查看>>
【笔记】【线性代数的本质】7-点积与对偶性
查看>>
bitbucket和Mercurial安装和相关
查看>>
不知道“严厉批评”算不算严厉处罚
查看>>
Docker(三):Dockerfile命令大全
查看>>
1.相关概念和准备工作
查看>>
『暗时间』读书笔记
查看>>
PHP中的(伪)多线程与多进程
查看>>
C# wave mp3 播放器探寻
查看>>
[转]QT之qss教程-Qt渐变色QGradient
查看>>
关于爬虫
查看>>
利用定时器的方式实现主动查询订单支付状态
查看>>
【Spring】Spring MVC原理及配置详解
查看>>
HttpListener Start 拒绝访问
查看>>
AndroidStudio 常用设置iLiam
查看>>
基于AgileEAS.NET SOA 平台SAAS架构技术的开源分销ERP系统-SmartERP.NET下载配置说明
查看>>