目录
一、并发编程可以抽象成三个核心问题
- 分工
- 同步/协作
- 互斥
二、分工
将当前 Sprint 的 Story 拆分成「合适」大小的 Task,并且安排给「合适」的 Team Member 去完成
这里面用了两个「合适」,将 Story 拆分成大小适中,可完成的 Task 是非常重要的。拆分的粒度太粗,导致这个任务完成难度变高,耗时⻓,不易与其他人配合; 拆分的粒度太细,又导致任务太多,不好管理与追踪,浪费精力和资源。(合适的线 程才能更好的完成整块工作,当然一个线程可以轻松搞定的就没必要多线程);
安排给合适的人员去完成同样重要,UX-UE 问题交给后端人员处理,很显然是有问题的 (主线程应该做的事交给子线程显然是解决不了问题的,每个线程做正确的事才能发挥作用)
并发中的常见的分工
- Executor
- 生产者-消费者模式
- Fork/Join
三、同步/协作
任务拆分完毕,我要等张三的任务,张三要等李四的任务,也就是说任务之间存在依赖关系,前面的任务执行完毕,后面的任务才可以执行,人在可以通过沟通反复确认,确保自己的任务可以开始执行。但面对程序,我们需要了解程序的沟通方式,一个线程执行完任务,如何通知后续线程执行
所有的同步/协作关系我们都可以用你最熟悉的 If-then-else 来表示:
if(前序任务完成){
execute();
}
else{
wait();
}
上面的代码就是说:当某个条件不满足时,线程需要等待; 当某个条件满足时,线程需要被唤醒执行,线程之间的协作可能是主线程与子线程的协作,可能是子线程与 子线程的合作, Java SDK 中 CountDownLatch 和 CyclicBarrier 就是用来解决线 程协作问题的
四、互斥
分工和同步强调的是性能,但是互斥是强调正确性,就是我们常常提到的「线程安全」,当多个线程同时访问一个共享变量/成员变量时,就可能发生不确定性,造成不确定性主要是有 可⻅性 、 原子性 、 有序性 这三大问题,而解决这些问题的核心就是互斥
来看下图,主干路就是共享变量,进入主干路一次只能有一辆⻋,这样你是否理解 了呢?「天下大事,分久必合」,Java SDK 也有很多互斥的解决方案,比如你⻢上就能想到 synchronized 关键 字,Lock,ThreadLocal 等就是互斥的解决方案
五、总结
资本家疯狂榨取劳动工人的剩余价值,获得最大收益。当你面对 CPU,内存,IO 这些劳动工人时,你就是那个资本家,你要思考如何充分榨取它们的价值
- 当一个工人能干的活(单线程),绝不让两个人来干(单线程能满足就没必要为了多线程)
- 当多个工人干活时(多线程),就要让他们分工明确,合作顺畅,没矛盾
当任务很大时,由于 IO 干活慢,CPU 干活快,就没必要让 CPU 死等当前的 IO, 转而去执行其他指令,这就是 榨取剩余价值 ,如何最大限度的榨取其价值,这就涉及到后续的调优问题,比如多少线程合适等。