线程和进程图解
工厂、车间、工人
并发编程可抽象成三个核心问题: 分工、同步/协作、互斥
学并发编程,透彻理解这三个核心是关键
分工
将当前 Sprint 的 Story 拆分成「合适」大小的 Task,并且安排给「合适」的 Team Member 去完成
关于分工,常见的 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,转而去执行其他指令,这就是榨取剩余价值,如何最大限度的榨取其价值,这就涉及到后续的调优问题,比如多少线程合适等
分工是设计,同步和互斥是实现,没有好的设计也就没有好的实现;在分工阶段,强烈建议勾划草图,了解瓶颈所在,这样才会有更好的实现
充分结合生活中的实际,并发问题,基本上都能在实际生活中找得到原型