【Java】《2小时搞定多线程》个人笔记(二)

简介: 【Java】《2小时搞定多线程》个人笔记

【Java】《2小时搞定多线程》个人笔记(一)https://developer.aliyun.com/article/1395300

并发和并行

并发和并行的前提

  • CPU的飞速发展,比如 i7 出现多核多线程。
  • 编程语言自身支持多线程,这一点很重要,比如Java天生具备多线程能力。
  • 一对一映射内核线程。
  • 充分利用操作系统资源。
  • 操作系统本身:操作系统对于多线程的利用也很关键,操作系统通过编程语言的逻辑进行多线程。调度是性能影响的关键。

理清两者概念

并发

image.png

实际上包含了两种概念,第一种:并发存在程序“并发性”,第二种:多个任务的执行状态是“并发”的。

这两种概念都有一个很好的比喻,也就是我们的大脑,我们大脑可以具备“并发性”,比如可以同时操作鼠标和键盘。另一个意义操作鼠标和键盘这两个动作是并发但不是并行的,同时画圆和画圈(需要经过一定的训练)可以看作是并行的。

并发存在程序“并发性”

  • 此时并发和并行的概念不在同一个维度。
  • 同一个时间可能有多个线程接替工作,给使用者的感受好像是在同时工作,比如边敲键盘,边操作鼠标,实际上是受到程序并发性的影响。
  • 不同的部分在无序或者同时执行,但是最终结果不影响。
  • 无论单核还是多核心,只要能得出正确结果,就具备并发性
  • 这时候和多个任务执行状态的概念是不在一个维度上的, 而是更高维度。

多个任务的执行状态是“并发”的

  • 这种情况下是逻辑上的“并行”,并不是真正的并行。
  • 重叠的时间段交替运行
  • 并发不一定并行
  • 并行一定并发
  • 并发,并发和并发的不同

并行

image.png

并行的例子就是两个动作物理上同时发生,比如边打游戏,边接电话这两个动作可以同时进行。

  • 并行是多个核心可以在同一个时间线物理上同时工作
  • 并行一定并发
  • 依托于现代处理的发展
  • 多核能力强化
  • 编程语言支持多线程

两者关系

image.png

上面的图可以得出几个概念

  • 并发不一定并行
  • 并行一定并发
  • 并行和并发是并行包含在并发的概念里面,所以并行的前提是并发

提问:并发程序一定是并行的么?

结论:并发程序不一定并行,但是并行程序一定是并发的。

不一定,因为单核处理器通过快速的上下文切换也可以达到类似并行的效果,实际上是利用抢占式的系统调用和分片式的系统调用完成的。

单核逻辑上同行运行叫做并发。上下文切换非常快,所以会认为是并行的。多核实现了物理上并行,核心和核心之间互相独立,可以真正意义上物理时间可以实现。

比喻:是一个人操作多条流水线,好像每一个流水线都可以处理任务。多个人在流水线上,一个流水线挂了可以由别的流水线接收。

并发继续拓展

  • 表面上多个任务执行状态。
  • 程序上的并发性也叫做并发。

高并发和多线程关系

多线程是解决高并发问题的解决方案之一,但是多线程不是高并发的唯一办法。

比如redis操作数据就是单线程实现的(保证原子性非常简单),因为没有上下文切换十分高效,它没有用到多线程却页解决了数据库高并发的问题,分担压力。

拓展:

  • 并行的程序执行效率取决于开发者的代码。
  • 取决于处理器的性能。
  • 操作系统的调度。

高并发的性能指标

  • QPS:每秒的查询数量,越高说明服务器可以承受的瞬间压力越大
  • 带宽:决定了例如视频网站的服务质量。
  • PV(Page View):也就是访问和点击量。
  • UV(Unique View):表示单个用户访问的次数,是对于PV的访问量和点击率
  • UV一定会小于PV
  • IP和UV:最大的区别是是否是同一个用户的操作决定,也就是Cookie
  • 两个不同的指标
  • 第一个指标 IP:拨号上网IP变动
  • IP是每个人单独IP,但是访问者的Cookie是一样的
  • IP+1,Uv不变
  • 第二个指标 UV:局域网同一个账户多个人使用
  • IP可能没有变但是Cookie在切换
  • IP没有变,UV+1
  • 并发连接数
  • 某个时刻同时接受请求数量
  • 服务器平均等待时间
  • 处理一个请求所需时间。

同步和异步/阻塞和非阻塞

同步和异步

区分关键点:被调用方的行为

同步

强调的是被调用者(服务器)行为,不是请求方的行为。没有得到结果之前,服务端不返回任何结果。

和阻塞的判断刚好相反。

再次强调是被调用者(服务器)行为,不是请求方的行为。

image.png

image.png

异步

调用之后服务端立刻返回结果(通常是一个通知)。

image.png

image.png

案例:烧水壶、买书

烧水壶:传统的铁壶需要等待水烧开才会有结果,电水壶只需要理解返回启动结果即可,因为后续水烧开之后会断电并且提醒。

买书:同步就是书店买书直到老板给出想要的书之前会一直被迫等待(被调用方的行为),网上买书下单之后直接通知结果过几天之后到货。

阻塞和非阻塞

关键:对于调用者而言的服务端状态

  • 站在线程状态角度
  • 站在线程发出请求之后请求方的角度

案例:烧水壶、买书

烧水壶:阻塞就是看着水一直到烧开,非阻塞就是烧水的时候间隔一段时间看一眼。

买书:阻塞就是拿到要买的书籍之前老老实实等待(调用方等待),非阻塞书店老板找书的过程中可以逛逛书店看看其他的书籍。

综合案例

综合案例用洗衣服的案例来理解。

同步阻塞

洗衣服丢到洗衣机,全程看着洗衣机洗完,洗好之后晾衣服。

同步非阻塞

把衣服丢到洗衣机洗,然后回客厅做其他事情,定时看看洗衣机是不是洗完了,洗好后再去晾衣服。(等待期间你可以做其他事情,比如用电脑刷剧看视频)。

异步阻塞

把衣服丢到洗衣机洗,然后看着洗衣机洗完,洗好后再去晾衣服(没这个情况,几乎没这个说法,可以忽略)。

异步非阻塞

把衣服丢到洗衣机洗,然后回客厅做其他事情,洗衣机洗好后会自动去晾衣服,晾完成后放个音乐告诉你洗好衣服并晾好了

常见问题汇总

线程和进程的相同与不同点

不同点:

  • 起源不同
  • 概念不同
  • 性能开销不同
  • 作用域不同
  • 拥有资源不同
  • 数量不同

相同点:生命周期

并发和并发

  • 并发和高并发是一个包含关系(并行包含并发),一个程序并行意味着一定是并发,但是并发可以模拟出并行的效果。
  • 并发有两种概念,如果是程序“并发性”,则并行和并发不在一个维度,可以任务无论单核或者多核只要结果正确就具备并发性。另外一个程序具备并发性也算是并发的说法。

多线程的弊端

  • 异构化任务无法用多线程完成的任务不如单线程高效。
  • 线程安全问题,比如共享变量互相覆盖。
  • 性能问题,比如上下文切换、缓存失效。

高并发是否意味着多线程

  • 多线程仅仅是高并发的解决方案之一,两者是两个不同的概念,不能混为一谈。
  • 多线程不是唯一办法,但确实是主要办法。

缓存、消息队列、锁是高并发的三架马车

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

从并发编程的角度对着四个概念进行再次整理。

同步异步:和队列有关,事情能不能委托给其他人来办。 阻塞非阻塞:和锁的机制有关,做一个工作的时候能不能抽空干别的事情。

洗衣机洗衣服:

  • 同步阻塞:开启洗衣机,并且全程盯着洗衣机工作。
  • 同步非阻塞,开启洗衣机,虽然还是要隔几分钟看洗衣机是否完成工作,但是期间可以干别的事情。
  • 异步阻塞:委托给洗衣机自己洗衣服,但是要全程盯着取出衣服最后把衣服晾了。
  • 异步非阻塞:告诉洗衣机自己洗衣服,工作完成之后洗衣机自动把衣服晾了,最后告知结果。

单核CPU上多线程的意义

  • 开启多个线程可以让耗时的任务交给后台处理,利用其他线程提供服务。
  • 程序不知道运行在单核还是多核,单核CPU也可以充分利用多线程提高资源利用率。


相关文章
|
安全 Java 调度
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第12天】 在现代软件开发中,多线程编程是提升应用程序性能和响应能力的关键手段之一。特别是在Java语言中,由于其内置的跨平台线程支持,开发者可以轻松地创建和管理线程。然而,随之而来的并发问题也不容小觑。本文将探讨Java并发编程的核心概念,包括线程安全策略、锁机制以及性能优化技巧。通过实例分析与性能比较,我们旨在为读者提供一套既确保线程安全又兼顾性能的编程指导。
|
2天前
|
Java
Java中的多线程编程:基础知识与实践
【5月更文挑战第13天】在计算机科学中,多线程是一种使得程序可以同时执行多个任务的技术。在Java语言中,多线程的实现主要依赖于java.lang.Thread类和java.lang.Runnable接口。本文将深入探讨Java中的多线程编程,包括其基本概念、实现方法以及一些常见的问题和解决方案。
|
2天前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第13天】 在Java开发中,并发编程是一个复杂且重要的领域。它不仅关系到程序的线程安全性,也直接影响到系统的性能表现。本文将探讨Java并发编程的核心概念,包括线程同步机制、锁优化技术以及如何平衡线程安全和性能。通过分析具体案例,我们将提供实用的编程技巧和最佳实践,帮助开发者在确保线程安全的同时,提升应用性能。
10 1
|
2天前
|
Java 调度
Java一分钟之线程池:ExecutorService与Future
【5月更文挑战第12天】Java并发编程中,`ExecutorService`和`Future`是关键组件,简化多线程并提供异步执行能力。`ExecutorService`是线程池接口,用于提交任务到线程池,如`ThreadPoolExecutor`和`ScheduledThreadPoolExecutor`。通过`submit()`提交任务并返回`Future`对象,可检查任务状态、获取结果或取消任务。注意处理`ExecutionException`和避免无限等待。实战示例展示了如何异步执行任务并获取结果。理解这些概念对提升并发性能至关重要。
17 5
|
3天前
|
Java
Java一分钟:线程协作:wait(), notify(), notifyAll()
【5月更文挑战第11天】本文介绍了Java多线程编程中的`wait()`, `notify()`, `notifyAll()`方法,它们用于线程间通信和同步。这些方法在`synchronized`代码块中使用,控制线程执行和资源访问。文章讨论了常见问题,如死锁、未捕获异常、同步使用错误及通知错误,并提供了生产者-消费者模型的示例代码,强调理解并正确使用这些方法对实现线程协作的重要性。
14 3
|
3天前
|
安全 算法 Java
Java一分钟:线程同步:synchronized关键字
【5月更文挑战第11天】Java中的`synchronized`关键字用于线程同步,防止竞态条件,确保数据一致性。本文介绍了其工作原理、常见问题及避免策略。同步方法和同步代码块是两种使用形式,需注意避免死锁、过度使用导致的性能影响以及理解锁的可重入性和升级降级机制。示例展示了同步方法和代码块的运用,以及如何避免死锁。正确使用`synchronized`是编写多线程安全代码的核心。
55 2
|
安全 Java 调度
Java一分钟:多线程编程初步:Thread类与Runnable接口
【5月更文挑战第11天】本文介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并讨论了多线程编程中的常见问题,如资源浪费、线程安全、死锁和优先级问题,提出了解决策略。示例展示了线程通信的生产者-消费者模型,强调理解和掌握线程操作对编写高效并发程序的重要性。
43 3
|
安全 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第11天】在Java并发编程中,线程安全和性能优化是两个重要的主题。本文将深入探讨这两个方面,包括线程安全的基本概念,如何实现线程安全,以及如何在保证线程安全的同时进行性能优化。我们将通过实例和代码片段来说明这些概念和技术。
4 0
|
4天前
|
Java 调度
Java并发编程:深入理解线程池
【5月更文挑战第11天】本文将深入探讨Java中的线程池,包括其基本概念、工作原理以及如何使用。我们将通过实例来解释线程池的优点,如提高性能和资源利用率,以及如何避免常见的并发问题。我们还将讨论Java中线程池的实现,包括Executor框架和ThreadPoolExecutor类,并展示如何创建和管理线程池。最后,我们将讨论线程池的一些高级特性,如任务调度、线程优先级和异常处理。
|
安全 Java
【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解
【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解