1,什么是并发?
在cpu角度讲,多个cpu的核同时在工作。从Java的角度将,JVM在同一时刻在处理多个线程的请求。2,为什么要并发?
并发适用于多核处理器,以解决单线程阻塞导致效率低的问题,尽可能利用cpu空闲等待时间。缺点:线程间的切换具有额外开销。(用户线程的上下文要复制到cpu线程上来执行)
3,cpu、进程、线程的关系
cpu:执行计算机指令 操作系统的进程:程序的一次执行 操作系统的线程:操作系统调度器的调度的基本单位,交由cpu执行 cpu的线程:存放要执行的数据、指令等,是cpu的基本执行单位处理器的线程,与操作系统的进程,是 N:N 的关系。
操作系统的进程,与操作系统的线程,是1:N的关系。 所以,处理器线程与操作系统线程之间是 N:N 的关系。 一个进程至少有一个线程。线程不能跨域进程与访问另一个进程的内容。备注:
通常cpu的线程和核心数对应,几核就是几线程。但是单个线程并不能让单个cpu核满载造成cpu浪费,于是有了超线程技术,即一个cpu核负责两个或多个线程的运行。4,多线程的使用方式
多线程的使用有两种:协同式和抢占式。 协同式的实现比较简单,由于是在当前线程主动触发其他线程并等待结果返回,对调用者来说是可以感知的,不存在线程安全问题。缺点是等待的过程是阻塞的,线程阻塞会造成一定程度的浪费性能。比如Lua。而Java采用抢占式。5,多线程争夺cpu使用权
cpu的基本调度单位是线程,由一个叫做“调度器(scheduler)”的操作系统的组件来调度。cpu的核会在一个 时间片 内执行用户线程的操作。调度器会根据线程的优先级和线程的饥饿程度(等待时间)两个因素来调度线程。6,Java的线程与进程
jvm的线程与进程,是对操作系统的线程与进程的一种封装,方便操作。jvm将操作系统的进程,封装为Process(抽象类),唯一实现类是ProcessImpl。有创建工具类ProcessBuilder。jvm对进程的封装提供非常少的api,因为制定者不主张在java中以创建进程的方式执行多任务。
jvm将操作系统的线程,封装为Runable接口,java.lang包下有两个实现类,Thread和Shutdown。Shutdown是用来执行JVM关闭的时候的钩子函数的。普通代码实际运行的时候,需要一个Thread类的对象来.start()来执行。这个.start()是一个synchronized方法,方法内部会调用native的.start0()交给操作执行。Thread类还提供很多native的方法来供调用。
java.concurrent包下有Callable接口,可以有返回值(Future模式)。
7,线程的缓存与一致性规范
计算机的cpu的运算速度与内存的读写速度相差好几个数量级,因此引入了高速缓存。每个cpu的线程单独配一个高速缓存。 带来的问题:缓存一致性(CacheCoherence)。为了解决缓存一致性的问题,要求各个处理器访问缓存时遵循一定的协议(比如:MESI协议)。 Java虚拟机有自己的内存模型,虚拟机通过操作系统可以操作cpu的线程和高速缓存,所以Java内存模型定义了如何解决缓存一致性的规范。8,线程间的数据通讯
协同式天然具备线程间的通讯能力。Java采用抢占式,线程只与主内存交互。如果线程间需要通讯的话,需要先将数据从线程自己的工作内存写回到主内存,另外一个线程再从主内容加载到它的线程。 每一个java线程拥有自己的工作内存,所有的java线程共用一个主内存。方便理解:
主内存对应java堆中的对象实例数据部分,物理硬件的主内存。 工作内存对应虚拟机栈中的部分区域,程序运行时主要访问读写的是工作内存。 这种理解是片面的不准确的,但刚接触的时候比较容易理解一些。参考资料:
- 以上内容为笔者日常琐屑积累,已无从考究引用。如果有,请站内信提示。