首页 > 编程语言 >【面试突击】并发编程、线程池面试实战

【面试突击】并发编程、线程池面试实战

时间:2024-01-23 23:04:10浏览次数:37  
标签:CAS AQS 队列 编程 面试 任务 线程 原理

欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!

在我后台回复 「资料」 可领取编程高频电子书

在我后台回复「面试」可领取硬核面试笔记


前言

最近在更新面试突击专栏,我把每一篇将字数都尽量控制在 2000 字以内,可能在文章里边写的没有那么细致,主要是提供一些 问题 以及 回答的思路 ,以及 面试中可能忽略的漏洞 ,所以在看完文章之后,如果自己简历中有这方面的内容的话,一定要认真去整理一份自己的回答,并且多查阅相关资料,如果看的文章少,就会导致学习到的内容太片面

并发编程

面试官为什么都喜欢问并发编程的问题?

如果面试的大一点的公司,用户量上来之后,那么并发包下的东西还是很容易会用到的,并且写代码时,如果对并发安全不算了解,那可能写完的代码存在许多并发上的问题,可能测试的时候没问题,到生产环境中造成严重后果!

我之前面试过唯品会,唯品会的面试官给我的印象就是很在乎你的基础,无论是并发、JVM、MySQL、Redis 原理,还是项目中使用到的技术,都会问你底层原理,我面试之后也问面试官了,为什么偏向于去问这么多技术的底层原理,面试官给的回答是因为只有了解底层的原理,你在使用的过程中才会更加注意他存在哪方面的问题,可以更好的去避免!


对于并发编程这块的内容,synchronized、CAS、AQS 的原理之前也写过一篇文章,详细内容可以点击:Java并发编程-synchronized解析


说说synchronized关键字的底层原理是什么?

下面来用 大白话 说一下原理:

synchronized 保证线程同步主要是依赖于两个 jvm 的指令:monitorenter、monitorexit 来实现的,比如说 synchronized 修饰一个代码块,那么进入代码块之前,执行 monitorenter 表示上锁,退出代码块之后,执行 monitorexit 表示解锁,以此来保证不同线程顺序执行这个代码块

并且 synchronized 在 jdk1.6 进行了优化,将锁分为了四种状态:无锁、偏向锁、轻量级锁、重量级锁,这 4 个状态会随着竞争激烈而逐渐升级,不过偏向锁在 jdk15 之后逐渐废弃,因为维护的开销比较大


能聊聊你对CAS的理解以及其底层实现原理可以吗?

CAS 操作需要 3 个参数:要写入的内存地址、预期值、要写入的值

CAS 的原理就是,去要写入的内存地址判断,如果这个值等于预期值,那么就在这个位置上写上要写入的值


CAS 存在一些缺陷:

  • 循环时间过长:如果 CAS 自旋一直不成功,会给 CPU 带来很大开销
  • 只能针对一个共享变量
  • 存在 ABA 问题:CAS 只检查了值有没有发生改变,如果原本值为 A,被改为 B 之后,又被改为了 A,那么 CAS 是不会发现值被改编过了的
    ABA 问题解决方案:为每个变量绑定版本号,A–>B–>A 加上版本号为:A1–>B2–>A3

了解 AQS 吗?底层原理是什么?

AQS 是抽象队列同步器,其实就是一个队列,存储的是线程,AQS 的作用就是 去管理线程加锁和解锁时的阻塞、唤醒

AQS 的原理:线程在获取锁失败之后,会被封装成 Node 节点假如到 AQS 阻塞等待,当获取锁的线程释放锁之后,会从 AQS 队列中唤醒一个线程,AQS 队列如下:

【面试突击】并发编程、线程池面试实战_线程池

这里推荐一篇讲解 AQS 源码非常好的文章:AQS源码详细解析参考文章



线程池的底层工作原理

接下来就不对线程池的细节进行讲解了,如果想要查看可以点击:线程池底层原理细节

线程池其实就是对线程做一个 池化 操作,用于线程不断创建、销毁的开销,可以重复利用线程,节省资源

线程池中的重要参数如下:

  • corePoolSize :核心线程数量
  • maximumPoolSize :线程池最大线程数量 = 非核心线程数+核心线程数
  • keepAliveTime :非核心线程存活时间
  • unit:空闲线程存活时间单位(keepAliveTime单位)
  • workQueue :工作队列(任务队列),存放等待执行的任务
  • threadFactory :线程工厂,创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等。
  • handler: 拒绝策略 ,如果阻塞队列满了之后,对于新加入的任务该如何处理

除了线程池的核心参数要掌握,任务提交到线程池中的执行流程也要了解:

【面试突击】并发编程、线程池面试实战_代码块_02


线程池的参数设置攻略

下边以几种设置的例子,来说明一下会出现的情况:

  • 如果将 maximumPoolSize 设置为 Integer.MAX_VALUE

这时,如果瞬间任务很多,核心线程都被占用,那么会无限创建线程去处理任务,导致消耗系统不断消耗资源去创建大量线程,如果任务提交速度大于线程处理速度,系统资源很快就会被耗尽,即使内存没有崩溃,也会导致 CPU 负载很高,所以要避免将 maximumPoolSize 设置的无限大

  • 如果在线程中使用无界阻塞队列

如果发生了调用超时,导致队列越来越大,那么会导致任务一直向阻塞队列中存放,内存飙升,甚至出现 OOM 问题

  • 自定义拒绝策略

其实可以自己去定义拒绝策略,如果线程池无法处理更多的任务了,可以在自定义的拒绝策略中,将拒绝的任务异步化持久化到磁盘中去,之后再通过一个后台线程去定时扫描这些被拒绝的任务,慢慢执行


如果线上机器突然宕机,线程池的阻塞队列中的请求怎么办?

如果宕机,重启之后,线程池阻塞队列中的任务就会全部丢失

如果想要解决这种情况的话,有这么一个 解决方案:在将任务提交到线程池中去的时候,先把任务在数据库中存储一份,并记录任务执行的状态:未提交已提交已完成,执行完之后的话,将任务状态标记为 已完成,如果宕机后,导致任务丢失,就可以去数据库中扫描任务,重新提交给线程池执行


标签:CAS,AQS,队列,编程,面试,任务,线程,原理
From: https://blog.51cto.com/u_16186397/9386394

相关文章

  • 《Java核心编程》PDF
    内容简介本书主要基于Java13来介绍Java核心编程相关的知识点,以及从Java8至Java13以来的新特性,主要内容包括:Java语言基础、面向对象编程、集合框架、异常处理、I/O处理、网络编程、并发编程、基本编程结构的改进、垃圾回收器的增强、使用脚本语言、Lambda表达式与函数式编程、St......
  • java基础面试知识点
    学习自javaGuideJava语言有哪些特点简单易学面向对象(封装,继承,多态)平台无关性(Java虚拟机实现平台无关性)支持多线程(C++语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而Java语言却提供了多线程支持)可靠性(具备异常处理和自动内存管理......
  • git笔试面试题
     收集整理几个git相关的笔试面试题 1、你们公司版本是如何管理的?细说一下 2、如何创建分支? 3、gitclone、gitpull、gitfetch、gitpush的区别是? 4、merge和rebase的区别是? 5、gitpull和gitpull--rebase的区别是? 6、代码提交到本地仓库后,发现提交日志写......
  • 区块链面试
    什么是web3?web2和web3的区别?PoW(工作量证明)和PoS(权益证明)有什么区别?比特币和以太坊有什么区别?什么是智能合约?公钥和私钥?简要说一下什么是dapp,dao,gamefi,defi?什么是Gas?你用一句话讲一下amm机制?你玩过一些什么应用?opensea和looksrare的区别?区块链有什么特征?1.去......
  • 【STM32使用Arduino编程0】Arduino_Core_STM32固件的安装和使用
    【STM32使用Arduino编程0】Arduino_Core_STM32固件的安装和使用对于STM32来说,使用Arduino编程可以大大降低编程难度,同时也可以使用Arduino的许多库。Arduino_Core_STM32介绍要使用Arduino对STM32进行编程需要使用相应的固件,目前官方的固件为Arduino_Core_STM32。对应的github......
  • 并发编程之协程
    协程1.什么是协程计算机中提供了:线程、进程用于实现并发编程(真实存在)。协程(Coroutine),是程序员通过代码搞出来的一个东西(非真实存在)。协程也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行(来回跳着执行)。例如:deff......
  • 并发编程之多线程
    多线程1.什么是线程就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线流水线的工作需要电源,电源就相当于cpu所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者......
  • 【网络编程】CS&BS架构_OSI七层、五层模型_三握四挥_Socket编程_粘包
    【一】CS&BS架构(1.1)CS架构产生的历史背景计算机网络的发展:20世纪60年代至70年代,计算机网络开始出现并得到广泛应用。最初的计算机网络主要是用于共享资源和实现远程访问,例如通过终端连接到中央计算机。这种模式下,中央计算机扮演着服务器的角色,而终端则扮演着客户端的角色。......
  • C# 线程本地存储 为什么线程间值不一样
    一:背景1.讲故事有朋友在微信里面问我,为什么用ThreadStatic标记的字段,只有第一个线程拿到了初始值,其他线程都是默认值,让我能不能帮他解答一下,尼玛,我也不是神仙什么都懂,既然问了,那我试着帮他解答一下,也给后面类似疑问的朋友解个惑吧。二:为什么值不一样1.问题复现为了方便讲......
  • 00-C语言编程技巧
    目录一.if(3==i)一.if(3==i)将if(i==3)的写法改成if(3==i):这样做的好处是当出漏写一个=号的时候,编译器会告知“attemptedassighnmenttoliteral”.(试图向常数赋值)//假如有这样一段代码#include<stdio.h>intmain(){inti=3;while(1){......