并发编程——基础概念(二)

本文系作者 chaoCode原创,转载请私信并在文章开头附带作者和原文地址链接。

违者,作者保留追究权利。

前言

并发编程在我们日常开发中是时时刻刻都有在用的,只不过大部分的代码底层已经帮我们去做了一些并发编程的安全处理,但是还是有很多情况下需要我们自己去控制,所以我们需要去了解学习并发编程,那么我们一步一步深入的开始学习。
如果有小伙伴没有看过之前的并发编程——基础概念(一)可以自行观看。

本篇为概念性的东西,可能比较冗长,请耐心解读,对于学习并发编程之前我们首先要知道这些基本的概念。

基础概念

1.澄清并行和并发

我们举个例子,如果有条高速公路 A 上面并排有 8 条车道,那么最大的并行车 辆就是 8 辆此条高速公路 A 同时并排行走的车辆小于等于 8 辆的时候,车辆就可 以并行运行。CPU 也是这个原理,一个 CPU 相当于一个高速公路 A,核心数或者线 程数就相当于并排可以通行的车道;而多个 CPU 就相当于并排有多条高速公路,而 每个高速公路并排有多个车道。

当谈论并发的时候一定要加个单位时间,也就是说单位时间内并发量是多少? 离开了单位时间其实是没有意义的。

俗话说,一心不能二用,这对计算机也一样,原则上一个 CPU 只能分配给一个 进程,以便运行这个进程。我们通常使用的计算机中只有一个 CPU,也就是说只有 一颗心,要让它一心多用同时运行多个进程,就必须使用并发技术。实现并发技术 相当复杂,最容易理解的是“时间片轮转进程调度算法”。

综合来说:
并发:指应用能够交替执行不同的任务,比如单 CPU 核心下执行多线程并非是 同时执行多个任务,如果你开两个线程执行,就是在你几乎不可能察觉到的速度不 断去切换这两个任务,已达到"同时执行效果",其实并不是的,只是计算机的速度太 快,我们无法察觉到而已。

并行:指应用能够同时执行不同的任务,例:吃饭的时候可以边吃饭边打电话, 这两件事情可以同时执行

两者区别:一个是交替执行,一个是同时执行。

image.png

2.高并发编程的意义、好处和注意事项

由于多核多线程的 CPU 的诞生,多线程、高并发的编程越来越受重视和关注。 多线程可以给程序带来如下好处。

充分利用 CPU 的资源
从上面的 CPU 的介绍,可以看的出来,现在市面上没有 CPU 的内核不使用多线 程并发机制的,特别是服务器还不止一个 CPU,如果还是使用单线程的技术做思路, 明显就 out 了。因为程序的基本调度单元是线程,并且一个线程也只能在一个 CPU 的一个核的一个线程跑,如果你是个 i3 的 CPU 的话,最差也是双核心 4 线程的运算 能力:如果是一个线程的程序的话,那是要浪费 3/4 的 CPU 性能:如果设计一个多线 程的程序的话,那它就可以同时在多个 CPU 的多个核的多个线程上跑,可以充分地 利用 CPU,减少 CPU 的空闲时间,发挥它的运算能力,提高并发量。

就像我们平时坐地铁一样,很多人坐长线地铁的时候都在认真看书,而不是为 了坐地铁而坐地铁,到家了再去看书,这样你的时间就相当于有了两倍。这就是为 什么有些人时间很充裕,而有些人老是说没时间的一个原因,工作也是这样,有的 时候可以并发地去做几件事情,充分利用我们的时间,CPU 也是一样,也要充分利用。

加快响应用户的时间
比如我们经常用的迅雷下载,都喜欢多开几个线程去下载,谁都不愿意用一个 线程去下载,为什么呢?答案很简单,就是多个线程下载快啊。

我们在做程序开发的时候更应该如此,特别是我们做互联网项目,网页的响应 时间若提升 1s,如果流量大的话,就能增加不少转换量。做过高性能 web 前端调优 的都知道,要将静态资源地址用两三个子域名去加载,为什么?因为每多一个子域 名,浏览器在加载你的页面的时候就会多开几个线程去加载你的页面资源,提升网 站的响应速度。多线程,高并发真的是无处不在。

可以使你的代码模块化,异步化,简单化
例如我们实现电商系统,下订单和给用户发送短信、邮件就可以进行拆分, 将给用户发送短信、邮件这两个步骤独立为单独的模块,并交给其他线程去执行。 这样既增加了异步的操作,提升了系统性能,又使程序模块化,清晰化和简单化。

多线程应用开发的好处还有很多,大家在日后的代码编写过程中可以慢慢体 会它的魅力。

3.多线程程序需要注意事项

线程之间的安全性
从前面的章节中我们都知道,在同一个进程里面的多线程是资源共享的,也就 是都可以访问同一个内存地址当中的一个变量。例如:若每个线程中对全局变量、 静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的:若有多 个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

线程之间的死锁
为了解决线程之间的安全性引入了 Java 的锁机制,而一不小心就会产生 Java 线程死锁的多线程问题,因为不同的线程都在等待那些根本不可能被释放的锁,从 而导致所有的工作都无法完成。假设有两个线程,分别代表两个饥饿的人,他们必 须共享刀叉并轮流吃饭。他们都需要获得两个锁:共享刀和共享叉的锁。

假如线程 A 获得了刀,而线程 B 获得了叉。线程 A 就会进入阻塞状态来等待 获得叉,而线程 B 则阻塞来等待线程 A 所拥有的刀。这只是人为设计的例子,但尽 管在运行时很难探测到,这类情况却时常发生

线程太多了会将服务器资源耗尽形成死机当机
线程数太多有可能造成系统创建大量线程而导致消耗完系统内存以及 CPU 的“过渡切换”,造成系统的死机,那么我们该如何解决这类问题呢?

某些系统资源是有限的,如文件描述符。多线程程序可能耗尽资源,因为每个 线程都可能希望有一个这样的资源。如果线程数相当大,或者某个资源的侯选线 程数远远超过了可用的资源数则最好使用资源池。一个最好的示例是数据库连接 池。只要线程需要使用一个数据库连接,它就从池中取出一个,使用以后再将它返 回池中。资源池也称为资源库。

多线程应用开发的注意事项很多,希望大家在日后的工作中可以慢慢体会它 的危险所在。

感谢诸君的观看,文中如有纰漏,欢迎在评论区来交流。如果这篇文章帮助到了你,欢迎点赞👍和关注。

posted @ 2021-08-06 09:42  不太自律的程序猿  阅读(203)  评论(0编辑  收藏  举报