[个人感悟] 多线程问题应该考察哪些问题? (Java篇)

在这里插入图片描述


前言

如何做一个合格的多线程开发者? 你真的懂多线程么?” 作为编程初学者被问的最多的问题, 本文就这个问题. 详细的讲讲对方究竟为什么要问这个问题, 并且回答问题的主要思路框架.

PS: 本文主体背景为Java语言. 其他语言应当为同理.


问题 - 单线程问题

  • 什么是进程?什么是线程? 什么是协程?

  • 如何创建一个线程? 线程有哪些状态? 其如何变化?

  • 如何停止一个线程? 如何优雅的停止一个线程?

问题 - 线程池问题

  • 什么是线程池?

  • 请描述下线程池的工作原理?

  • 线程池的核心参数有哪些?

  • 实战问题1: 一般如何设计这些参数?

  • 实战问题2: 开发中都使用哪些线程池? 都是如何使用的?

问题 - 锁 - 线程竞争

  • 什么是锁?

  • 锁的种类有哪些?

  • 锁升级过程?

  • [Java] synchronized锁的实现原理?

  • [Java] RentrankLock锁的实现原理?

  • [Java] 乐观锁的实现原理? 缺点? 如何解决缺点?

  • 如何防止超买问题? 如何防止超卖问题?

问题 - 多线程集合工具

  • 线程安全的集合工具有哪些?

  • 为什么说ArrayList是非线程安全的?

  • 如何处理ArrayList的非线程安全问题? 有什么代替的线程安全结构? 实现原理?

  • 为什么说HashMap是非线程安全的?

  • 如何处理HashMap的非线程安全问题? 有什么代替的线程安全结构? 实现原理?

  • 实战问题1: 开发过程中, 都使用哪些线程安全的集合工具?

问题 - 多线程并发工具

  • 现在有A和B, 2个线程? 如何使A线程先执行, B线程后执行?

  • 现在有A和B, 2个线程? 如何使A线程执行2次, B线程执行1次?

  • 现在又ABCDE, 5个线程? 如何使AB先并发执行, CDE随后并发执行?

  • 现在又ABCDEF, 6个线程? 如何保证同时只有5个线程同时执行?

问题 - 实战

  • 实战问题1: 开发过程中都会遇到哪些多线程问题? 都是如何解决的?

  • 实战问题2: 单例模式时候的多线程问题?


回答 & 目的

本文的主旨是探讨多线程问题设计的目标, 此处应当不涉及具体问题的解答. 为梳理多线程相关的知识点, 为考察自己做一个简单的疏漏分析, 也为检查他人对于多线程的掌握做一个评判标准.

问题 - 单线程问题

在询问单线程的时候, 应当需要考察读者对于多线程的理解. 这与将军带兵打仗时一个道理, 如何合理的带兵打仗一样? 什么是士兵? 应当如何合理的派遣士兵.

  • 线程的宏观认知
    首先, 进程应当是操作系统内执行程序的基本单位. 但是进程之间的数据是不共享的. 为了方便操作, 引出线程和协程的概念, 其主要有2点优势. 1. 相比进程, 其声明和销毁更具有轻量化的特征. 2. 进程之间资源共享.

  • 线程的生命周期 & 状态转换
    随后, 当对于线程有一个宏观的了解后, 应当考察对于线程的创建, 线程的生命周期, 线程的管理. 等几个问题. 就其本质都是线程的生命周期问题. 线程的生命周期问题通常有3态模型和5态模型. 如下所示:

此处关于线程3态, 5态, 7态模型的问题, 先以3张图示掠过, 后期会进行详细叙述. 我们工作中常用的模型即是线程的5态模型. 3态模型较为简单, 7态模型较为复杂.

  • 线程关键问题1 - 如何创建线程
    如何创建线程. 对于Java程序来说, 一般是包含4种方式, 其实都是一种创建的方式. 即Thread newThread = new Thread();
  1. Thread newThread = new Thread();
  2. Thread newThread = new Thread( new Runnable() { xxx});即重写Runnable接口. 其本质还是通过声明Thread对象.
  3. 通过Future接口和Callable接口. 其本质也是通过Thread newThread = new Thread();来进行声明的.
  4. 通过线程池. 线程池其本质是一个享元模型的设计模式, 其支持Runnbale, Future, Callable接口的提交, 其本质也是维护了一个FutureTask对象, 其也是一个new Thread的操作.

详细可见[]

  • 线程关键问题2 - 如何销毁线程
    如何销毁线程. 我们可以通过3种方式:
  1. 强制关闭. 前后通过try–catch的方式进行异常捕获, 此处会立即关闭线程. 不推荐, 因为可能部分线程内的任务并没有结束, 会导致异常. 举个例子, 比如处理10条消息存储, 当存储到5条消息时候, 手动stop, 此时会导致后面5条消息无法处理. 当然我们还可以通过异常捕获或者数据库事务的方式进行问题解决. 此处为非线程相关的问题.
  2. 通过isInterrupted()方法, 进行标志位退出.
  3. 通过其他标志位退出. 此方法和isInterrupted()类似.
  • 线程关键问题3 - 线程的start()和run()方法有什么区别?
  1. start()方法. 调用后, 启动调用的线程, 随后其线程由创建状态转变为就绪态, 等待进行执行. 其过程会执行start()-run()-stop()顺序执行线程.
  2. run()方法. 调用后, 执行的线程为当前线程, 在main方法内通常为主线程, 单纯的方法调用, 线程的状态未发生任何变化.

小结: 上述5个问题, 可以对于单线程问题有一个全面的了解. 从浅入深, 非常适合.

问题 - 线程池问题

线程池问题, 也是Java内对于线程的考察必问的问题之一. 我们在真实的工作场景中, 对于线程而言, 线程都不是单打独斗的, 也不是自己管理的, 我们通常使用线程池进行处理. 即便Java上层抽象出了Executors和ExecuteService等上层抽象, 我们对于线程池还是需要一定量的了解.
首先, 我们通常问的问题也是线程池的声明, 并且包含其哪些关键参数. 其次, 需要考察, 线程池的种类, 线程池的运行原理. 如果你想考察其是否有真实的线程池经理, 可以问线程池遇到的问题, 线程池是否需要OOM问题, 多个线程池应当如何管理, 如何监控线程池的运行状态等等. 如下给出一些简单的问题的简要回答.

  • 宏观 - 什么是线程池?
    线程池是用于线程管理的线程集合, 其用于管理多个线程的使用. 其中通常包含核心线程和临时线程, 因为线程的声明和销毁通常较为消耗服务器性能, 所以, 通常使用享元模型的线程池进行管理. 其通常包括 核心线程, 临时线程, 消息队列, 消息工厂等常见元素.

  • 请描述下线程池的工作原理?
    线程池通常包括 核心线程, 临时线程, 消息队列, 消息工厂等几个常见组成部分. 当新的任务提交至线程池时:

  1. 线程池会判断当前核心线程是否达最大值. 若没有, 则创建一个新的核心线程, 并将新的任务分配给新的核心线程. 若达到最大值, 则进行下一步.
  2. 如果核心线程数目已经满了. 线程池会将查看当前线程池的消息队列, 若消息队列未满, 其会将新的任务放入消息队列, 若满, 则进行下一步.
  3. 如果消息队列已满. 线程池会查看当前临时线程是否达到最大值, 若未满, 其会创建临时线程, 并将新的任务分配给临时线程, 且临时线程在执行结束后, 会经过规定时间的等待, 随后进行销毁. 若临时线程也达到最大值, 则进行下一步.
  4. 如果临时线程数已满, 线程池会根据设置的拒绝策略进行拒绝任务的执行, 通常有抛出异常等.
  • 线程池的核心参数有哪些?
    其主要包括. 核心线程数, 总线程数目, 临时线程存活时间, 临时线程存活时间单位, 消息队列, 线程创建工厂, 拒绝策略. 这7个核心参数. 其常见的类型具体可以看.

  • 实战问题1: 一般如何设计这些参数?e
    截至JDK1.8, 线程池通常包含, 单线程池SIngleThreadPool, 常量线程池FixedThreadPool, 变量线程池CacheableThreadPool, 定时线程池ShceduleTheadPool, ForkJoinThreadPool 这几种类型.

  1. 核心线程数, 总线程数目. 通常设置成一样的. 防止频繁的生成和销毁线程产生开销, 缺点是, 线程可能声明太多, 占用内存空间.
  2. 消息队列. 通常使用规定长度的队列, ArrayListBlockingQueue. 防止内存溢出, CacheableThreadPool使用的是无限长度的队列, 可能导致OOM问题.
  3. 核心线程数, 总线程数目. 其有时候根据CPU密集型和IO密集型进行区分, CPU密集型通常为可用CPU核心数目的1倍, IO密集型通常为
    可用CPU核心数目的2倍. 但是具体的数值可以进行性能压测得出最完美的数值.
  • 实战问题2: 开发中都使用哪些线程池? 都是如何使用的?
    开发过程中, 通常使用FixedThreadPool, ForkJoinThreadPool这2种.
  1. 使用时需要手动声明线程池, 而非直接放入JDK的内置的Common线程池内.
  2. 通常推荐使用ForkJoinThreadPool, 对于任务较为频繁的线程池, 对于任务不频繁的使用FixedThreadPool.
  3. 且注意使用额定长度的消息队列和合适的拒绝策略.
问题 - 线程池问题

当多个线程之间出现竞争的时候, 通常使用锁来处理, 让后获取的一方进行等待或者直接抛出异常. 从初期的Thread.yeild()和Thread.join()方法的线程通信, 后期衍生出synchronized和violatile关键字, 到最后的ReentanckLock. 其经历了一些列的衍生过程. 对于Java内部锁的考察通常就考察这一些列的使用和原理. 当然有时还会考察操作系统种, “如何产生死锁问题?” 和 "如何避免死锁问题?’ “如何解决死锁问题?”这3个问题.

  • 宏观 - 什么是锁?
    Java内的锁. 即是指定一个Java的内容空间, 防止其他线程进行访问. 宏观意义上, 锁可以是任何资源.

  • 锁的种类有哪些?

  1. 从锁的抽象来说. 乐观锁和悲观锁.
  2. 从锁的使用. 读锁, 写锁, 读写锁.
  3. 从Java的使用, synchronized锁, ReentranckLock锁.
  4. 从Java锁升级的过程. 偏向锁, 排他锁.
  5. Mysql内, 页锁, 表锁, 行锁等.
  • 锁升级过程?
    略.

  • [Java] synchronized锁的实现原理?
    class文件上设置当前持有的线程线程号.

  • [Java] RentrankLock锁的实现原理?
    同上?

  • [Java] 乐观锁的实现原理? 缺点? 如何解决缺点?

  1. 乐观锁. 设置一个值, 开始和结束进行比较, 如果出现变化则锁失效.
  2. CAS. ABA问题.
  3. 设置版本号和值. 双重判断.
  • 如何防止超买问题? 如何防止超卖问题?
  1. update where count > 1
  2. 加锁.
  • “如何产生死锁问题?” / "如何避免死锁问题?’ /“如何解决死锁问题?
  1. 死锁的产生. 各个线程 or 进程都持有资源, 不肯释放. 剩余的资源又无法满足任何一个线程或者进程.
  2. "如何避免死锁问题. 每次分配资源时, 进行检测.
  3. 如何解决死锁问题? 当死锁已经产生, 那么只有让当前持有资源的线程和进程放弃手中的资源. 可以选择1个1个的释放进程, 也可以全部清空.
问题 - 多线程集合工具

多线程集合. 我们常见的集合为List, Set, HashMap. 其对于多线程问题, 通常出现的问题就是写覆盖, 即A线程写入, B线程覆盖的问题. 这样就衍生出了一些列的多线程集合, LinkedBlockingQueue, ConcurrentHashMap等.

  • 线程安全的集合工具有哪些?
    LinkedBlockingQueue, ConcurrentHashMap.

  • 为什么说ArrayList是非线程安全的?
    A线程取值, B线程取值, A写入, B写入. B取的是错误的值, 并且会覆盖A的值.

  • 如何处理ArrayList的非线程安全问题? 有什么代替的线程安全结构? 实现原理?、
    LinkedBlockingQueue.

  • 为什么说HashMap是非线程安全的?
    写覆盖.

  • 如何处理HashMap的非线程安全问题? 有什么代替的线程安全结构? 实现原理?
    ConcurrentHashMap. Segment, or 锁当前Hash槽.

  • 实战问题1: 开发过程中, 都使用哪些线程安全的集合工具?
    LinkedBlockingQueue和 ConcurrentHashMap 较多.

问题 - 多线程并发工具

多线程并发工具通常有 CountdownLatch, CycleBarrier 和 Sephore 3种. 前2种主要用于设置线程之前的前后关系, Sephore 用于处理线程的并发量, 这个用的不是特别多.

  • 现在有A和B, 2个线程? 如何使A线程先执行, B线程后执行?
    CountdownLatch CycleBarrier

  • 现在有A和B, 2个线程? 如何使A线程执行2次, B线程执行1次?

  • 现在又ABCDE, 5个线程? 如何使AB先并发执行, CDE随后并发执行?
    CountdownLatch CycleBarrier

  • 现在又ABCDEF, 6个线程? 如何保证同时只有5个线程同时执行?
    Sephore

问题 - 实战
  • 实战问题1: 开发过程中都会遇到哪些多线程问题? 都是如何解决的?
  1. 声明ForkJoinPool线程池.
  2. 监控线程池使用和内存使用. 合理设置线程池大小.
  3. 合理使用消息队列和拒绝策略. 其实就是微服务中的 限流和降级.
  • 实战问题2: 单例模式时候的多线程问题?
public class PersonService {
	private static volatile boolean singleton= null;
	public PersonService getPersonService(){
		if(null == singleton) {
			synchronized(PersonService.class){
						if(null == singleton) {
							singleton = new PersonService ();
						}
			}
		}
		return singleton;
	}

}
  1. 双重锁判断.
  2. 使用synchronized进行排他锁.
  3. 使用二次判断. 防止第一个线程已经创建了对象, 随后第二个线程也经过第一重判断, 未进行第二重判断进行的重复问题.
  4. 此处为懒汉模型. 开发中还可以使用饿汉模式, 和 枚举方式 进行单例模式.

经过上述的问题梳理, 个人认为应当对于Java的多线程应当属于一个中级掌握的阶段.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/677816.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中信建投证券信息技术部PMO高级经理张子洋受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 中信建投证券股份有限公司信息技术部PMO高级经理张子洋先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾,演讲议题为“浅谈项目管理标准化的建设及实践分享”。大会将于6月29-30日在北京举办,敬请关注! 议题…

[Flask]开源项目--基于Faster R-CNN的在线害虫识别系统

项目演示效果可见视频: 【现已开源】害虫在线识别系统-基于pytorchflaskhttps://www.bilibili.com/video/BV1yx4y1u74y/?vd_source80963105a0c8d89bb119f3ebca249b22!!!---本项目仅供交流学习,禁止商用---&#xff0…

【外汇天眼】选择外汇EA的关键:策略适配、风险控制与稳定性评估

外汇EA(Expert Advisor)是外汇交易市场中广泛使用的自动化交易系统。它们通过预定义的规则和算法自动执行交易,旨在为交易者提供便捷的交易体验,同时提高交易效率和准确性。本文将从策略选择、风险控制和稳定性评估三个方面&#…

1panel服务器面板迁移Docker容器存储路径

1panel服务器面板迁移Docker容器存储路径 1、停止Docker服务 找到容器菜单,在配置中点击停止。 2、迁移Docker容器目录 Docker默认存储目录/var/lib/docker 2.1、无已部署容器 删除docker目录,避免额外的磁盘空间占用。 2.2、有已部署容器 若需保留…

AIGC绘画设计基础——迄今为止你还没学会用AI提高工作效率吗?

对于我来说,在工作效率提升,绘画创意生成,视频制作等等方面,都有了质的飞跃提高。 下面我分别从不同方面说一下AI带给我的提效,并且也分享我用的好用工具给到大家。 一、工作提效 我的本职工作是从事设计管理工作&am…

YOLOv5改进 | 注意力机制 | 添加SimAM注意力机制【全网独家+附完整代码】

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 压缩和激励模块(SE)以及空间通道注意力模块(CBAM)的注意力机制取得了巨大成功。本文介绍了一…

功能强大且专业的PDF转换软件PDF Shaper Professional 14.2

PDF Shaper Professional是一款适用于Windows的程序,可让您在计算机上处理PDF文件。 要开始使用PDF Shaper Professional,您需要在Windows计算机上下载并安装该程序。您还应该有合适的驱动程序和编解码器来处理计算机上的文本和图形。 安装程序后&#…

从零开始入门 LangChain

前言 最近一直在做 RAG 相关的内容,也学习了一段时间 LangChain 框架的用法。 本篇文章中将和大家讲述什么是 LangChain ,以及 LangChain 解决了现在大模型发展的哪些问题,然后会讲解LangChain 中基础的概念和组件。在此基础上,…

经纬恒润成功研发LRR610雷达先进算法!

好消息!经纬恒润搭载Arbe芯片组的LRR610 4D成像雷达算法开发出先进的后点云算法,并已圆满完成集成工作,这标志着智能驾驶感知系统迈向了一个新的里程碑。 经纬恒润自主开发的成像雷达算法,可以有效地跟踪数百个运动和静止目标&am…

亿级数据过滤和布隆过滤器

如何高效实现存在判断 在刷抖音时你有刷到过重复的推荐内容 吗?这么多的推荐内容要推荐给这么多的用户,它是怎么保证每个用户在看推荐内容时,保证不会出现之前已经看过的推荐视频呢?也就是说,抖音是如何实现 推送去重…

java 工作排序(Job Sequencing Problem)

给定一个作业数组,其中每个作业都有一个截止期限,如果作业在截止期限之前完成,则可获得相关利润。此外,每个作业都占用一个单位时间,因此任何作业的最小可能截止期限都是 1。如果一次只能安排一项作业,则最…

开源规则引擎LiteFlow项目应用实践

本文介绍基于开源规则引擎LiteFlow,如何开发规则设计器,在低代码平台中集成规则引擎,并在项目中实现应用的效果。由于低代码平台使用规则引擎实现了逻辑编排的需求,所以本文中的叫法为“逻辑设计”、“逻辑编排”、“逻辑流引擎”…

RabbitMQ学习笔记(二)SpringAMQP的使用、消息转换器

文章目录 前言3 SpringAMQP3.1 介绍3.2 简单队列模型3.3 工作队列模型3.4 发布/订阅模型3.4.1 Fanout广播模型3.4.2 Direct定向模型3.4.3 Topic通配符模型 3.5 消息转换器 前言 RabbitMQ学习笔记(一)RabbitMQ部署、5种队列模型 3 SpringAMQP 3.1 介绍 AMQP(Adva…

白酒:产地与白酒品牌形象的建设与推广

云仓酒庄豪迈白酒作为中国白酒市场中的知名品牌,其产地与品牌形象的建设与推广对于提升品牌竞争力和市场份额具有重要意义。产地作为白酒品质和特色的重要标志,对于品牌形象的塑造和推广具有关键作用。 首先,云仓酒庄豪迈白酒的产地是其品质和…

AI降痕工具使用指南:如何有效降低AIGC疑似度

随着人工智能技术的突飞猛进,AI生成内容(AIGC)已被广泛用于学术论文撰写中,提高效率同时也带来了原创性的挑战。面对日益严格的学术审查,一个突出的问题是:使用AI代写的论文能否通过内容检测?因…

第二证券股票杠杆:4分钟直线涨停!这一赛道,AH股集体爆发!

今日早盘,A股继续小幅震动收拾,首要股指涨跌互现,两市个股跌多涨少,成交有萎缩的趋势。 盘面上,医药、中字头、旅游、房地产等板块相对活跃,混合实践、玻璃基板、AI手机PC、光刻机等板块跌幅居前。 “中字…

活动投票小程序源码系统 礼物道具活动多多 前后端分离 带完整的安装代码包以及搭建教程

系统概述 在当今数字化快速发展的时代,小程序已成为连接用户与商家、内容与服务的重要桥梁。特别是活动投票类小程序,因其便捷性、互动性和参与性,受到了广大用户的热烈追捧。为了满足市场对高质量、易操作的活动投票小程序的需求&#xff0…

别慌!不知道如何处理#开头的字符串时,需要先了解一下什么是NCR

最近进行接口测试时抓包发现请求响应中有类似下面这些字符 起初试图对这些编码尝试各种decoder操作来一探其真身,遗憾的是均已失败告终(后来发现,这些编码可以在浏览器中正常显示)。最后得知这种奇怪的编码格式并不是编码,而是一种…

ClickHouse 实现用户画像(标签)系统实践

文章目录 前言用户画像概述用户画像系统介绍用户画像系统的需求描述用户画像系统的需求分析用户画像系统的架构 关键技术实现(Clickhouse SQL)分析阶段运营阶段 基于ClickHouse的用户画像系统的优点 前言 本文介绍一个ClickHouse应用案例—用户画像系统…

AI工具:解锁智能时代办公自动化的新篇章

工欲善其事,必先利其器。 随着AI技术与各个行业或细分场景的深度融合,日常工作可使用的AI工具呈现出井喷式发展的趋势,AI工具的类别也从最初的AI文本生成、AI绘画工具,逐渐扩展到AI思维导图工具、AI流程图工具、AI生成PPT工具、AI…