程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的。
当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。
进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器 等),也有的程序只能启动一个实例进程(例如网易云音乐、360 安全卫士等)
单核 cpu 下,线程实际还是串行执行的。操作系统中有一个组件叫做任务调度器,将 cpu 的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于 cpu 在线程间(时间片很短)的切换非常快,人类感觉是同时运行的 。总结为一句话就是: 微观串行,宏观并行
一般会将这种线程轮流使用 CPU 的做法称为并发, concurrent
多核 cpu下,每个核(core) 都可以调度运行线程,这时候线程可以是并行的。
引用 Rob Pike 的一段描述:
例子
家庭主妇做饭、打扫卫生、给孩子喂奶,她一个人轮流交替做这多件事,这时就是并发
家庭主妇雇了个保姆,她们一起这些事,这时既有并发,也有并行(这时会产生竞争,例如锅只有一口,一个人用锅时,另一个人就得等待)
雇了3个保姆,一个专做饭、一个专打扫卫生、一个专喂奶,互不干扰,这时是并行
@Slf4j(topic = "c.Sync") public class Sync { public static void main(String[] args) throws InterruptedException { log.debug("start sleep"); TimeUnit.MILLISECONDS.sleep(2000); log.debug("end sleep"); log.debug("do other thing"); } }
@Slf4j(topic = "c.Async") public class Async { public static void main(String[] args){ new Thread(() -> { log.debug("start sleep"); try { TimeUnit.MILLISECONDS.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("end sleep"); }).start(); log.debug("do other thing"); } }
可以发现。执行睡眠操作时的线程名称已经改变了,而且操作的顺序已经发生了改变。
以调用方角度来讲,如果
设计
多线程可以让方法执行变为异步的(即不要巴巴干等着)比如说读取磁盘文件时,假设读取操作花费了 5 秒钟,如果没有线程调度机制,这 5 秒 cpu 什么都做不了,其它代码都得暂停…
结论
案例
计算 1 花费 10 ms
计算 2 花费 11 ms
计算 3 花费 9 ms
汇总需要 1 ms
注意:需要在多核 cpu 才能提高效率,单核仍然时是轮流执行