前言
因为要最近要面试,冲刺挑战一下,下面是准备的并发篇面试题,其实我对并发也不太清楚,没怎么接触实战。具体如下:
- 前言
一、线程篇
这里讲解线程和线程相关分析
一、为什么用到多线程,那些地方用到多线程
提高系统效率,充分利用CPU
二、开发中多线程可能遇到那些问题,如何解决
1.线程下载,2.异步发送短信,3.异步回调,响应支付,4.Aop异步处理日志,5.复杂逻辑,6.定时执行job任务,7.数据备份
三、多线程生命周期
1.线程安全:多个线程共享一个全局变量,导致脏数据。解决:lock、syn或cas无锁机制
2.获取异步结果:主动业务Id
3.死锁:诊断工具检测死否有发生死锁现象
四、为什么使用线程池
频繁创建和销毁线程,对CPU消耗巨大,考虑线程复用机制
五、如何保证线程池不停止
死循环
六、使用线程池优点
1.复用线程创建销毁,2.减少CPU调度,3.统一维护管理多线程
七、线程池创建方式:Executors
可缓存
设置固定长度
可定时
单例(核心:封装一个构造函数)
八、线程复用机制
创建线程,不会停止,一直运行
九、线程池原理
1.提前预热创建线程,保证一直运行
2.执行任务交给队列实现存放(生产者)
3.正在运行线程不断从队列获取任务(消费者)调用run
十、Java阻塞技术
先进先出原则
十一、停止线程池
shutdown()
十二、线程失败了怎么样
捕获异常,记录日志到库,job定时作补偿
二、分布式事物解决方案
背景
传统项目多数据源RPC远程调用方发起请求成功后,但是调用方突然挂了会产生分布式事物
核心思想
采用最终一致性,短暂延迟是允许,最终要保持数据一致性
解决方案
内部:
1、ita+atomic适用传统项目
2、基于MQ补偿解决分布式事务,例如RabbitMQ
3、RocketMQ自带事务消息
4、基于LCN解决,原理:代理我们自己数据源重写方法来实现假关闭,传递消息全局ID
5、基于Seata解决分布式事务问题,原理同LCN。区别:LCN易造成死锁,Seata使用日志逆向生成sql实现回滚
外部:
采用类似支付宝异步回调+主动查询
三、并发安全篇
1、高并发中如何保证脏读数据
答:只有全局变量存在线程安全,多线程共享同一个全局变量会出现线程安全问题
使用Syn(自动)或lock(手动),并发包cas无锁机制保证线程问题
2、Syn(自动)或lock(手动) 区别
3、乐观锁和悲观锁区别
答:乐观锁速度快,不会阻塞,适用于多读的应用类型,这样可以提高吞吐量
四、高并发解决方案
核心:web项目,网页大部分是静态资源占用带宽,需要使用前后端分离架构
前端:
1、动静分离模式,静态资源放置第三方对象存储服务器(自带CDN)
2、静态资源压缩成.min格式
3、nginx+lua+openrests对静态资源布局缓存
后端:
1、微服务网关和nginx对接口限流、保护、白名单、黑名单
2、redis缓存减轻热数据导致的压力,集群部署,读写分离,提高吞吐量
3、采用MQ异步处理或者多线程提高程序运行速度
4、jvm性能调优和tomcat参数调整提高吞吐量
5、mysql服务器性能优化,读写分离、分表分库提高吞吐量
五、如何保证redis和mysql数据一致性
1、更改数据清空缓存,存在时间差
2、操作数据时,将数据更新到redis,达到一致性
3、使用MQ订阅mysql的binlog日志,再推送到redis
六、如何保证并发情况下MQ消息不丢失
1、生产者确认机制,成功不投递,失败就重试3次。消费者消费成功改状态,失败手动ACK
七、数据库优化
1、开启慢查询定位。
2、sql语法优化避免not null,in,inner join关联三个表等关键字。
3、数据量大避免使用1 = 1。
4、设置索引。
5、使用union代替临时表。
6、避免sql处理逻辑,代码来处理更快。
7、分表分库,字段大使用分表。
8、读写分离。
9、热点数据使用缓存处理
八、线上服务器CPU问题
- 8.1、内存爆满什么原因,怎么解决
1、被攻击挖矿:限制端口,内网访问
2、并发量增高:集群,分布式化,设置tomcat最大线程、请求
3、代码死循环:应用报警系统或者手写报警设置阈值,达到阈值通知邮件,定时执行top命令
- 8.2、怎么定位程序飙升CPU的线程
1. 创建线程时候一定要定义线程组名字,通过java VisualVM排查那个线程,再定位到代码
2. linux先用 top -h 看看飙升的程序pid,再使用阿里诊断工具:阿尔萨斯。使用命令 thread -n 3,定位到哪个线程。
九、所有定时任务挂掉,怎么处理
1、使用keepalived实现心跳检测,当job任务宕机,自动触发重启,多次失败通知邮件
十、访问网站比较卡
访问人数多:可能是并发,服务器响应慢原因
访问人数少:可能是带宽,1M=128kb/s。
十一、并发包有哪些
我们通常所说的并发包也就是 java.util.concurrent 及其子包,集中了 Java 并发的各种基础工具类。
1、提供了比 synchronized 更加高级的各种同步结构,包括 CountDownLatch、CyclicBarrier、Sempahore 等,可以实现更加丰富的多线程操作
2、各种线程安全的容器,比如最常见的 ConcurrentHashMap、有序的ConcunrrentSkipListMap
3、各种并发队列实现,如各种 BlockedQueue 实现,比较典型的 ArrayBlockingQueue、 SynchorousQueue 或针对特定场景的 PriorityBlockingQueue 等。
4、强大的 Executor 框架,可以创建各种不同类型的线程池,调度任务运行等,绝大部分情况下,不再需要自己从头实现线程池和任务调度器。
十二、AQS设计原理(锁)
1、Lock锁底层原理
基于AQS+CAS+LockSupport锁实现
2、Synchronized与Lock锁之间的区别
Lock基于AQS封装结合CAS实现,升级过程需要自己代码实现;
Synchronized基于C++封装,JDK1.6优化可以实现锁的升级
十三、Threadlocal内存泄漏
1、谈谈你对Threadlocal的理解
提供每个线程都缓存一个局部变量副本,将变量与线程绑定
2、应用场景
1. spring事物模板
2. springMVC获取request参数
3. APO、springCloud服务追踪框架源码
4. javaWeb项目toncat请求
5. 创建线程接收请求--》aop目标参数
3、底层实现原理
set方法
1. 获取当前主线程
2. 获取当前主线程的theadLocalMap对象
3. 存在对象就插入新value,不存在就创建一个空的theadLocalMap
get方法
1. 获取当前线程
2. 再获取当前线程的theadLocalMap数据
4、为什么线程缓存的是theadLocal对象
theadLocalMap可以存放多个theadLocal对象
theadLocal只能存放一个值。(相当于key)
5、Threadlocal为什么会引发内存泄漏
因为每个线程都有独立的threadLocalMap对象,其中key就是ThreadLocal,value就是变量值
key为threadLocal作为entry对象的key,当ThreadLocal指向null时候,Entry对象key就会变成key,该对象就一直无法被回收。
6、Threadlocal内存泄漏解决方案
1、每次remove时候将不要的数据移除避免内存泄漏
2、每次set时候需要清除之前key为null