Skip to main content

Java 并发编程的基石

· 11 min read
Zeffon Wu

学习并发编程,对于线程与进程、线程与多线程、并行与并发、并发与高并发、同步与异步、阻塞与非阻塞之间的概念与关系,需要进一步的理解。本篇学习于慕课网悟空老师的《Java 并发编程的基石》

前文

学习并发编程,对于线程与进程、线程与多线程、并行与并发、并发与高并发、同步与异步、阻塞与非阻塞之间的概念与关系,需要进一步的理解。本篇学习于慕课网悟空老师的《Java 并发编程的基石》

正文

线程、进程和多线程

进程
  1. 指的是程序的一次执行。在用户下达运行程序的命令后,就会产生进程。
  2. 进程就是程序(这里可以理解为我们编写的代码)的真正运行实例,是资源分配的基本单位。
线程
  1. 线程是 CPU 的基本调度单位,每个线程执行的都是进程代码的某个片段
  2. 在进程上下文中执行的一系列指令
进程与线程的 联系

操作系统`包

多个进程的容器,而每个进程又都是容纳`多个线程的容器。

进程与线程的 异同
  1. 相似点:生命周期
  2. 起源不同: 计算机系统先有进程后有线程,起初只有进程,没有线程的概念。因为微处理器的的处理速度远远高于外设(键盘鼠标等等),才诞生了线程,线程的诞生是为了提高程序的运行效率
  3. 概念不同: 进程是操作系统分配资源和调度的基本单位,线程是 cpu 运行调度的基本单位
  4. 内存共享方式不同: 通常进程之间内存不会共享(比如浏览器不会访问视频播放软件的内存),通常需要高级技巧 IDC 才能实现进程间通信实现内存共享,而线程之间的内存共享则比较容易
  5. 拥有的资源不同: 线程本身是进程的一部分,所以每个线程拥有的资源肯定少于进程,而线程之间共有的内容主要是代码片段,不共有的主要是线程的堆栈(独立的内存)
  6. 数量不同: 一个进程里面可以有很多线程,但是至少会有一个线程
  7. 开销不同: 线程的创建和终止比进程短,同一个进程内部的线程之间的切换比进程之间的切换要快,同一个进程的各个线程之间共享内存和资源文件,可以不通过内核进行通信
多线程

如果一个程序允许运行两个或以上的线程,那么它就是多线程程序。多线程是指在单个程序中运行多个线程。

  • 多线程的作用:
  1. 最主要的目的就是提高 CPU 利用率(1.提高处理速度 2.避免无效等待 3.提高用户体验、避免卡顿和缩短等待时间)
  2. 便于编程建模
  3. 计算机性能定律:摩尔定律失效,阿姆达尔定律登上舞台
  • 多线程的局限:
  1. 性能问题:上下文切换带来的消耗
  2. 异构化任务(任务结构不一样)很难高效并行
  3. 带来线程安全问题:包括数据安全问题(例如 i++总数不一致)以及线程带来的活跃性问题(线程饥饿、死锁)。

并行、并发和高并发

并行

真正的同时运行---在同一时刻,有多个任务同时执行。例如,在多核处理器上,有两个线程同时执行同一段代码。单核处理器是无法实现并行的,因为单核处理器无法在同一时刻执行多个任务。

并发
  1. 形容多个任务的执行状态
  • 两个或多个任务可以在重叠的时间段内启动,运行和完成
  • 并行(两个线程同时执行)一定是并发
  • 并不一定意味着并发一定要求是并行
  1. 并发性的简称
  • 不同的部分可以无序或同时执行,且不影响最终的执行结果
  • 在不同核心数的计算机上的不同表现
  • 此时,并行和并发的概念并不同一维度上
高并发
  1. 同时有很多个请求发送给服务器系统,服务器能够同时并行处理很多请求。
  2. 高并发和多线程的联系和不同
  • 高并发可以认为是一种状态(大量的请求同时到达我们的服务器所带来的一种结果);多线程是一种编程方式,它是一种解决方案,它所解决的是恰恰是防止高并发带来的线程安全问题或者是性能问题。
  • 多线程和高并发的关系:其中一种重要的解决方案
  • 高并发并不意味着是多线程:Redis
  1. 高并发指标
  • QPS(Queries Per Second) 每秒查询数(每秒钟的请求数)
  • 带宽
  • PV(Page View) 综合浏览量,指的是一天之内访问量
  • UV(Unique Visitor) 一天之内用户访问数量
  • IP 和 UV 的区别
  • 并发连接数(The number of concurrent connections)
  • 服务器平均请求等待时间(Time per request:across all concurrent requests)

同步与异步、阻塞与非阻塞

同步与异步:被调用者是否主动告诉调用者结果。 阻塞与非阻塞就是程序在等待调用结果(消息,返回值)时的状态。

同步
  1. 在发出一个同步调用时,在没有得到结果之前,该调用就不返回。
  2. 同步这里指的是被调用者(也就是服务器)的行为,而不是请求方的行为。在没有得到结果之前,服务端就不返回任何结果。
异步
  1. 在发出一个异步调用后,调用者不会立刻得到结果,该调用就返回了。
  2. 调用在发出之后,服务端会立刻返回,告诉调用方'我收到你的请求了,我会处理的'。这样调用方知道被调用方已接收到请求了,就可以去执行其他命令了。
阻塞
  1. 阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
  2. 我是调用者,我调用一个东西之后,结果返回前,我不能做别的事
非阻塞
  1. 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
  2. 我是调用者,我调用一个东西之后,结果返回前,我还能做别的事
  • 阻塞与非阻塞站在线程状态的角度
  • 阻塞与非阻塞站在线程发出请求(通常是 HTTP 请求)的角度
联系

举一个烧水壶的例子进行说明。

  • 两种水壶:
  1. 一种是把水烧开了不会提醒的。
  2. 一种是会提醒发出呜呜声响的。
同步阻塞

选用不会提醒的水壶进行烧水,在烧水期间,由于我是笨,不知道水什么时候会烧好,只好坐在水壶前等待,这样就不能去做其他事情。一直在水壶前盯着,直到水壶把水烧开拿下来。

同步非阻塞

选用不会提醒的水壶进行烧水,在烧水期间,我很聪明,虽然不知道什么时候会烧好,但是我能在这期间去做其他事情,只要时不时来检查一下是否烧好了就好了。烧好拿下来就好了。

异步阻塞

选用会提醒的水壶进行烧水,在烧水期间,由于我比较笨和老实,我还是只能坐在水壶前,所以也不能去做其他事情。直到水壶烧开发声提醒时,才把水壶拿下来。

异步非阻塞

选用会提醒的水壶进行烧水,在烧水期间,我很聪明知道时间不可浪费,我可以跑去做其他事情,等到我听到水壶烧开发声提醒时,我才过去把水壶拿下来,这样也是能完成烧水任务的。