十分钟读懂:Java并发——CSP模型

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 main

import (
    "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的channel
channel := 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并没有经过广泛的生产环境检验,因此不推荐在生产环境使用

写在最后

  • 第一:看完点赞,感谢您的认可;
  • ...
  • 第二:随手转发,分享知识,让更多人学习到;
  • ...
  • 第三:记得点关注,每天更新的!!!
  • ...
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容