准备写个关于java并发编程系列的博客。首先说一下,感谢方腾飞,魏鹏,程晓明先生所著的《Java并发编程的艺术》一书,给了我很多参考。
那么下面就开始正文。
一:什么是并发
通俗点说就是在同一个时间段内,计算机可以执行多个程序。
二:并发的目的是什么
并发的目的当然就是为了让程序运行得更快。让客户(程序使用者)更加舒适。
三:初识并发编程
并发编程先要了解一个概念:上下文切换。单核处理器也是支持多线程执行代码的,CPU可以通过给每个线程分配CPU时间片来实现多线程机制。CPU不停的切换线程执行,给不同的线程分时间片,由于每个时间片的时间很短很短,会让人产生这是在并行的感觉。每次切换线程时都需要保存上一个线程的状态(不然下次回来怎么知道这个线程执行到哪里啦?)。从一个线程任务保存执行状态再到下一次CPU切换回当前线程并且重新加载了这个状态的过程就是一次上下文切换。
可能有朋友对并行和并发有些误解,通俗的说:并发其实就是ABC(多线程)三个人排在一条队列,各自做各自的事情,但是要听警察(CPU)的指令来分配谁先做,谁后做事,其实每个时间点真实做事情的人只有一个,但是由于指令很快,外人(程序调用者)是感受不出来的,感觉是同时发生。而并行其实就是ABC排3条队列,同时做事(互不干扰)。当然,java多线程的通信本来其实就是依靠共享变量,锁甚至是队列来操作的,本身线程和线程之间是没办法直接“交流”的。对于多核处理器,一般多个物理 CPU 在多个程序之间多路复用,以此来提高对计算机资源的利用率
并发编程一定快?不一定!就从累加来说,网上很多例子都能看出来,效率完全是看循环累加的次数的。并发编程是指可以在有足够的硬件资源和网络带宽下扩展程序的效率,假如服务器的带宽只有1Mb/S,再怎么并发编程去多线程下载资源,也不可能超过这个值的。
四:如何让程序的执行变快
1:减少CPU上下文的切换。参考《Java并发编程的艺术》,减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。
a: 无锁就不用解释了,本身多线程竞争锁就会消耗资源,如果不采用锁来做并发,选择一致性Hash算法等操作也可以减少 上下文切换
b: CAS算法的实质也是无锁
c: 使用最少线程。这个就是要根据任务来创建线程,或者采用线程池来管理线程,不要创建过多的冗余线程来增加系统的 负担。
d: 协程有点调度者的样子,就是在单线程里面实现多任务的调度,维持多线程切换。(是不是有点像分布式事务解决方案 中的协调者感觉?不过人家可不是一个线程吆)
2:java重排序。Java源代码到最终实际执行的指令序列,会经历3种重排序。
源代码-------->编译器优化重排序--------->指令级并行重排序--------->内存系统重排序-------->最终执行的指令
Java重排序依赖于JMM(java内存模型),JMM有4种内存屏障指令,分别是
LoadLoad Barriers:load1 LoadLoad load2确保Load1数据的装载先于Load2及所有后续装载指令的装载
StoreStore Barriers: store1 StoreStore store2 确保store1数据对其他处理器可见(刷新到内存)先于store2及所有后续存储 指令的存储
LoadStore Barriers:load1 LoadStore store2 确保Load1数据装载先于store2及所有后续的存储指令刷新到内存
StoreLoad Barriers:store1 StoreLoad load2 确保Store1数据对其他处理器可见,先于Load2及所有后续装载指令的装载