Java高频面试题
2021-05-20 17:27:26 4 举报
AI智能生成
Java JUC并发相关面试题 思维导图笔记
作者其他创作
大纲/内容
JUC
(1)请你谈谈对volatile的理解
1.volatile是Java虚拟机提供的轻量级同步控制
1.1保证可见性(多个线程之间数据同步)
1.2不保证原子性
1.3禁止指令重排
2.JMM(java内存模型规范,不存在)
2.1可见性
2.2原子性
number++在多线程下是非线程安全的,如何不加synchronized解决?
2.3VolatileDemo代码演示可见性+原子性
2.4有序性
重排1
禁止指令重排小节
3.在哪些地方用过volatile?
3.1单例模式DCL
3.2
(2)CAS你知道吗?
比较并交换
CAS底层原理?如果知道谈谈对UnSafe的理解
atomicInteger.getAndIncrement()
UnSafe
CAS是什么
unsafe.getAndAddInt
底层汇编
CAS的缺点
循环时间长开销很大
只能保证一个共享变量的原子操作
会引出ABA问题?
(3)原子类AtomicInteger的ABA问题?原子更新引用?
ABA问题怎么产生?
原子引用
时间戳原子引用
(4)集合不安全
1.ArrayList是线程不安全,请编码一个不安全的案例并给出解决方案
使用Vector
Collections.synchronizedList(new ArrayList<>())
new CopyOnWriteArrayList<>();
2.Set不安全
Collections.synchronizedSet(new HashSet<>());
new CopyOnWriteArraySet<>();
3.Map不安全
Collections.synchronizedMap(new HashMap<>());
new ConcurrentHashMap<>();
(5)公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈理解,手写自旋锁
公平锁和非公平锁
是什么
区别
题外话
可重入锁(递归锁)
是什么
ReentrantLock/Synchronized就是一个典型的可重入锁
可重入锁最大的作用是避免死锁
ReentrantLockDemo
自旋锁
独占锁(写锁)/共享锁(读锁)/互斥锁
ReadWriteLockDemo
CountDownLatch
(6)CountDownLatch/CyclicBarrier/Semaphore使用过吗?
CountDownLatch
CyclicBarrier
Semaphore
(7)阻塞队列知道吗?
队列+阻塞队列
为什么用?有什么好处?
BlockingQueue的核心方法
抛出异常组
特殊值组
子主题
子主题
架构梳理+种类分析
ArrayBlockingQueue:由数组组成的有界阻塞队列
LinkedBlockingQueue:由链表结构组成的有界(默认为Integer.MAX_VALUE)阻塞队列
PriorityBlockingQueue:支持优先级排序的无界阻塞队列
DelayQueue:使用优先级队列实现的延迟无界阻塞队列
SynchronousQueue:不存储元素的阻塞队列,也即单个元素的队列
LinkedTransferQueue:由链表结构组成的无界阻塞队列
LinkedBlockingDeque:由链表结构组成的双向阻塞队列
用在哪里
生产者消费者模式
传统版
ProdConsumer_TraditionDemo
阻塞版
ProdConsumer_BlockQueueDemo
线程池
消息中间件
(8)线程池用过吗?ThreadPoolExecutor谈谈你的理解?
为什么使用线程池,优势?
线程池如何使用?
线程池的几个重要参数?
7大参数
1.corePoolSize:线程池中的常驻核心线程数
2.maximnumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于等于1
3.KeepAliveTime:多余的空闲线程的存活时间。当前线程池数量超过corePoolSize时,当空闲时间达到KeepAliveTime值时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止
4.unit:KeepAliveTime的单位
5.workQueue:任务队列,被提交但尚未被执行的任务。
6.threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可
7.handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)
线程池的磁层工作原理
1.创建线程池后等待提交任务请求
2.当调用execute()方法添加一个请求任务时
如果正在运行的线程数量小于corePoolSize,立刻创建线程执行任务
如果当前正在运行的线程数量>=corePoolSize,将这个任务人放入队列
如果队列已满或者正在运行的线程数量<maximumPoolSize,创建非核心线程运行这个任务
如果队列已满并且正在运行的线程数量>=maximumPoolSize,启动饱和拒绝策略来执行
3.当一个线程完成任务时,它会从队列中取下一个任务来执行
4.当一个线程超过一定的等待时间以后(KeepAliveTime)时又会触发判断
当前运行的线程数>corePoolSize,就将该线程停掉
当线程池的所有任务完成以后,最终它会收缩到corePoolSize的大小
(9)线程池用过吗?生产上你如何设置合理参数?
线程池的拒绝策略
内容
JDK内置的拒绝策略
AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行
CallerRunsPolicy:“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新的任务量
DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
DiscardPolicy:直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种解决方案。
以上内置拒绝策略均实现了RejectedExecutionHandler接口
你在工作中,单一/固定数量/可变三种创建线程池的方法,你用哪个多?超级大坑!
答案是一个都不用,我们生产上只能使用自定义的
Executors中JDK已经提供了,为什么不能用?
1)FixedThreadPool 和 SingleThreadPool 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM(堆内存溢出)
2)CachedThreadPool 和 ScheduledThreadPool 允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM
你在工作中是如何使用线程池的,是否定义过线程池使用
合理配置线程池你是如何考虑的?
CPU密集型
IO密集型
第一种
第二种
(10)死锁编码以及定位分析
是什么?
产生死锁主要原因
系统资源不足
进程运行推进的顺序不合适
资源分配不当
代码
解决
**<font color="red"></font>**
unsafe.getAndAddInt(this, valueOffset, 1);
getAndAddInt
0 条评论
下一页