《Java 多线程实战系列》- 01 基本概念与底层原理

简介: 《Java 多线程实战系列》- 01 基本概念与底层原理

多线程实战系列

第一章 基本概念与底层原理

01 串行、并行、并发

欢迎大家来学习「多线程编程」课程,本章节呢我们主要会讲解多线程编程的一些相关基本概念,以及它的底层实现原理。本小节主要讲述的是串行、并行以及并发,这三个基本的概念。

本节的目标呢,主要是有两个:

第一,了解「串行、并行、并发」这三个概念的一些含义;

第二,是本小节的重点,要对并行、并发这两个概念有一个清晰的认识,了解他们之间的区别。

串行

好的,那我们先来看一下第一个概念,串行(Sequential)

它的定义,简单的来讲呢,就是在同一时间里,我们只能做一件事情,而且是要按照顺序依次进行的。

那在程序上来看呢,就是后面的代码段,必须要等到前面的代码段执行完毕之后,才能执行。

咱们来看一个生活中常见的例子,我们现在有钱了,买了套房子,马上就要开始装修了,但是呢我们钱不多了,现在的经费有限,只请得起一个师傅来装修房屋。

他一共有三件任务,第一项任务是拆墙,第二项任务是安装水电线,第三项任务是刷墙和铺地板。

跟师傅沟通之后,得知拆墙得用 2 天,安装水电线要 1 天,刷墙和铺地板也要 3 天。你看,如果这一个师傅从头到尾装修下来后,总需要耗费的时间就是 2 + 1 + 3 = 6 天,一共要花费 6 天的时间才能完成装修房子的整个任务。

因此呢,我们去算它的总耗时,就是每一个任务完成时间,进行一个累加,它们的和就是它的总耗时。

并行

接着,我们来看第二个概念,并行(Parallelism)。

它的定义,简单的来讲呢,就是在同一时刻,很多个任务可以同时开始进行,而且这些任务之间彼此没有依赖关系。

继续用房子装修作为案例。假设我们又有钱了,现在的经费非常充足,咱可以请三个师傅。

每个师傅可以负责他自己所对应的那个任务,比如王师傅他只需要是拆墙,李师傅只需要安装水电线,陈师傅只需要去刷墙和铺地板。此时你看,在条件允许的情况下,他们三个师傅就可以同时开干了。

这时候,我们再来看一下图,可以很清楚地看到,整个装修房屋的工程呢,只需要三天时间就可以完成了。

因此,在装修房屋的整个任务中,咱们采用了并行这个方式呢,可以让整个任务的总耗时更少,而实质上你可以发现,它是取决于耗时最长的内建子任务所需要的时间。

哪个任务的耗时最长呢?在图中可以看出,是刷墙和铺地板,需要 3 天。

并发

接着,我们来看第二个概念,并发(Concurrency)。

它的定义,也很简单,它是采用的是交替的方式,主要是利用等待某件事情完成的时间,去做其他的事情。

比如,你开始做饭的时候,可以先把米下锅,然后再去洗菜、炒菜,甚至中途还可以按一下洗衣机洗衣服。

继续用房子装修作为案例。此时,我们不小心又变穷了,现在的经费呢又不足了,只请得起一个师傅。

师傅开始干活了,他现在干的第一件事情,是刷墙和铺地板,这个任务的耗时,是三天的时间。要注意,装修的时候,咱刷完墙、铺好地板之后,是不是还得让它风干了才行?假设,刷墙、铺地板要耗费 2 天,全部好之后,最后 1 天就留着让它风干。

那你想,在风干的这个阶段里,咱师傅其实是没活干的,那就可以安排他去安装水电线呀。工作调整后,是不是就可以把风干的这么一天的时间节省下来,去完成了安装水电线的任务。当水电线的安装任务完成后,墙壁和地板的风干也结束了,是不是就在 3 天的时间里,同时把这两个任务都完成了?

接下来,他就可以进行拆墙的任务了,再花费 2 天的时间即可。

因此,整个装修房子的任务,只需要 5 天的时间,因为我们把风干的这一天节省了下来,同时去完成了安装水电线的工作。

并发 & 并行

通过前面的讲解,相信大家对串行、并行、并发这三个基本概念有了一定的了解。

接下来,让我们重点来讲解一下「并行与并发」之间的关系以及区别。

先看第一个图,好比现在只有一个 CPU,它同时面对了 A、B、C 三个任务,在同一时刻,一个 CPU 只能执行同一个任务。

在 CPU 中,首先去执行了任务 A,在执行任务 A 的过程当中,可能会碰到外力的一些阻碍,而导致了任务 A 暂时进入等待。

在等待的过程中,此时 CPU 是空转的,那如果想提高我们 CPU 的利用效率,来多节省点儿时间,该怎么办呢?

在等待任务 A 的过程中,我们可以把 CPU 拿来执行其他任务,比如任务 B。当我们去执行任务 B 的时候,可能也会碰到类似的,需要继续等待的情况。

这时候,也许 A 和 B 都依然是等待的状态,不过没事儿,我们可以继续去完成任务 C。在执行 C 的过程当中呢,我们发现 A 已经就绪了,那 CPU 此时就可以转回头去执行它。

你看,在我们的 CPU 里面,执行任务的时候,其实会不断地进行切换,通过这样的交替、反复的过程去实现更高效地完成任务。

CPU 在执行任务的时候,它的运行速度,实际上是非常非常快的。

从宏观层面上看,人类肉眼是无法感知得到这个切换间隙的,在我们看来,它从未中断过,是一直在执行的。所以,在我们人类看来,这些任务 A、B、C,都是同时就完成了的。

但是在微观上而言,因为在同一时间呢,CPU 只能完成一件任务。任务 A、B、C,实际上就是交替完成的,这就是并发。

但如果我们的资源比较充足,就跟我们前面装修的例子一样,经费充足的情况下,可以同是请三个师傅来开工,那效率一下子就上去了。

对于计算机来说,如果我们有三个 CPU,每个 CPU 都可以投入执行对应的任务。比如第一个 CPU 执行任务 A,第二个 CPU 执行任务 B,第三个 CPU 执行任务 C。

那这三个任务,同时开始执行,那它们的完成时间当然就更快了,这就是并行。

如果说,我们目前仍然只有三个 CPU,但需要处理 10 个任务的话,会发生什么不同吗?

实际上不会,一定要明白一个不变的事实,在同一时间里,一个 CPU 只能完成一件任务。此时,三个 CPU 那也只能有三个任务可以去执行,剩下的七个任务,也是需要进行等待的。

小结

通过前面的小案例,咱们详细讲解了串行、并行、并发等几个概念,相信大家对这些基本概念,都有了一个初步的了解,那我们现在来小结一下。

这个并发的出现,我们可以看到它肯定是比传统串行的系统的效率,提高了不少,还极大地节省了时间。

就像前面的案例中,我们只有一个师傅的时候,如果是按干完一件任务再干下一件的顺序,那效率肯定是不高的。

但是采用了并发的方式后,可以把装刷墙、铺地板后的风干环节,合理地规划出来,就能节省出一天的时间,就足够拿来安装水电线了。

不过,在并发的过程中,也会带来了一些额外的性能开销。在 CPU 内部,它从一个任务中切换去完成另外一个任务的时候,是需要进行系统调度和上下文切换的,这个过程中都会带来一些性能开销。

关于 CPU 性能上的问题,我们后面再去做更细致的分析和讲解吧。

另外一个,多核 CPU 的出现,使并行成为了可能,极大程度上地提高了我们现在计算机的处理能力啊,像四核、八核的 CPU 已经非常普遍了,它们的性能特别的强,非常猛。

目前,大型的互联网公司,因为业务比较庞杂,加上海量的数据需要处理,哪怕你有一两台电脑性能很好的机器,恐怕也是不行的,他们如何解决呢?

在企业中,一般都会采用集群的搭建方式,十台机器不够,就上一百台机器,往上加就好了。这样就有足够的性能,能够支持去应对一些很大规模、很复杂的任务了。

目录
相关文章
|
2天前
|
缓存 Java 开发者
Java字面量详解:概念、分类与使用实例
本文介绍了Java字面量的概念、分类及应用。
23 11
|
7天前
|
Java Linux 调度
硬核揭秘:线程与进程的底层原理,面试高分必备!
嘿,大家好!我是小米,29岁的技术爱好者。今天来聊聊线程和进程的区别。进程是操作系统中运行的程序实例,有独立内存空间;线程是进程内的最小执行单元,共享内存。创建进程开销大但更安全,线程轻量高效但易引发数据竞争。面试时可强调:进程是资源分配单位,线程是CPU调度单位。根据不同场景选择合适的并发模型,如高并发用线程池。希望这篇文章能帮你更好地理解并回答面试中的相关问题,祝你早日拿下心仪的offer!
26 6
|
29天前
|
存储 Java 程序员
Java的基础概念一
### Java编程基础简介 #### 一、注释 注释用于解释代码,不会参与编译和运行。Java支持三种注释: - **单行注释**:以 `//` 开头。 - **多行注释**:以 `/* ... */` 包围。 - **文档注释**:通常用于生成开发文档。 #### 二、关键字 关键字是被Java赋予特定含义的英文单词,全部小写,且在代码编辑器中有特殊颜色标记。常用的如 `class` 表示定义一个类。
Java的基础概念一
|
27天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
12天前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
|
19天前
|
Java 数据安全/隐私保护
Java的基础概念(二)
本文介绍了Java编程语言中的运算符和表达式,涵盖算术运算符、赋值运算符、关系运算符、逻辑运算符、三元运算符等。重点讲解了算术运算符的使用,如加减乘除取余,并强调了整数除法和取余的特殊性。同时,详细说明了隐式转换与强制转换的概念及应用场景,以及字符串和字符的拼接规则。通过多个案例演示了不同运算符的实际应用,包括数值拆分、自增自减、三元表达式的使用等。最后简要提及了运算符的优先级,指出小括号具有最高优先级。
|
29天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
29天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
29天前
|
监控 Java API
探索Java NIO:究竟在哪些领域能大显身手?揭秘原理、应用场景与官方示例代码
Java NIO(New IO)自Java SE 1.4引入,提供比传统IO更高效、灵活的操作,支持非阻塞IO和选择器特性,适用于高并发、高吞吐量场景。NIO的核心概念包括通道(Channel)、缓冲区(Buffer)和选择器(Selector),能实现多路复用和异步操作。其应用场景涵盖网络通信、文件操作、进程间通信及数据库操作等。NIO的优势在于提高并发性和性能,简化编程;但学习成本较高,且与传统IO存在不兼容性。尽管如此,NIO在构建高性能框架如Netty、Mina和Jetty中仍广泛应用。
42 3
|
29天前
|
安全 算法 Java
Java CAS原理和应用场景大揭秘:你掌握了吗?
CAS(Compare and Swap)是一种乐观锁机制,通过硬件指令实现原子操作,确保多线程环境下对共享变量的安全访问。它避免了传统互斥锁的性能开销和线程阻塞问题。CAS操作包含三个步骤:获取期望值、比较当前值与期望值是否相等、若相等则更新为新值。CAS广泛应用于高并发场景,如数据库事务、分布式锁、无锁数据结构等,但需注意ABA问题。Java中常用`java.util.concurrent.atomic`包下的类支持CAS操作。
64 2