Files
Hui-s-notebook/并发.md
lostecho 0e31c0d985 add file
2024-05-13 20:50:11 +08:00

170 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
创建线程命名有意义,方便回溯
不通过 Executor 方法创建,使用 ThreadPoolExecutor 方式
必须回收自定义的 ThreadLocal 变量,尤其在线程池场景
高并发时,同步调用应该去考虑锁的性能损耗
能无锁就不要用锁
能锁区块就不要锁方法
能用对象锁就不要用类锁
使用阻塞获取等待锁的方式中,必须在 try 代码块之外,并且在加锁方法与 try 代码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在 finally 中无法解锁
try 中没有加锁 lock. lock ()就解锁 lock. unlock ()会抛出 IllegalMonitorStateException 异常
try 和加锁之间有代码报错,就不会执行 finally 方法报错释放锁
分布式锁优先使用 redis 锁,而不是数据库锁
## 线程池中提交一个任务的流程是怎样的?
使用 executor() 来提交一个工作线程submit 会放在一个 Future 里面,返回 future
提交之后就判断当前worker是都达到核心线程数最大值如果未达到就创建线程并执行任务
如果达到了核心线程最大数,就将该任务放入队列中
如果队列已满,就 addWorker 创建新线程处理任务,如果达到最大线程数,就执行拒绝策略,默认为抛出异常
## 线程池中有几种状态?分别是如何变化的?
ctl 变量AtomicInteger表示状态
RUNNING会接受新提交的任务
SHUTDOWNshutdown ()不再接受新的任务,已有任务会执行完成
STOPshutdownNow ()不接受新的任务,已有任务也会中止
先修改状态,避免新任务进来
TYDING所有线程都终止后会进入该状态等待terminated
TERMINATEDterminated ()方法执行后进入该状态
## 如何优雅的停止一个线程
开启线程execute ()无需返回值submit (),需要有返回值,通过 Future. get ()获取
Thread t1 = new Thread()
t1.stop(), 该方法会直接停止已经废弃stop 方法会释放 sync 锁ReentrantLock 不会释放
使用 interrupt 方法Thread. getCurrent. isInterrupted 可以接受到中断的信号,但是线程自己控制是否停止, 睡眠时被中断会抛出InterruptedException
## 线程池的核心线程数、最大线程数该如何设置?
CPU 密集型任务,线程计算任务多,核心线程数+1避免线程切换时间
IO 密集型任务CPU 利用率不高,线程等待时间长,核心线程数 x2避免 CPU 闲置
线程数=CPU 核心数*(1+等待时间/运行总时间)
## 如何理解 Java 并发中的可见性?
多线程修改变量时,一个线程修改了一个变量,然后其他线程可以立刻读取到这个变化的值修改时,如果在缓存就不能被其他线程读取到,使用 volatile 关键字确保读取从内存读取,写入同时写入缓存和内存
## 如何理解Java并发中的原子性
CPU 按照时间片切换,读取值后被切换,其他线程修改了,但是切换回来不会再去读取该值,而是直接去修改该值,需要通过锁机制来保证原子性
## 如何理解 Java 并发中的有序性?
![[Pasted image 20240512214620.png]]
指令重排序,正常应该先初始化再返回地址
编译器优化,修改了执行顺序
通过锁和 volatile 关键字避免
## ForkJoinPool所解决的问题是什么
RecursiveTask继承ForkJoinTask
当任务可以拆分的时候,就将任务拆分后分不同的线程处理,最后再将所有的计算结果累加
可以指定执行的线程数量,默认是机器的线程数量
## ThreadPoolExecutor的底层实现原理
addWorker 方法会新开线程
如果已经达到了最大核心线程,就会提交到队列中,有空闲的线程就会执行,队列已满会新开线程,直到最大线程数,超过队列就会拒绝新任务
## ForkJoinPool 拆分任务底层实现分析
新开一个线程会拆封任务,然后拆分两个线程 join 等待,然后继续拆分任务,直到达到最大线程数据设置
执行 compute 方法创建一个队列,把任务放进队列中,然后第一个线程取出该任务,将该大任务拆分,放入队列中,任务 1fork创建一个自己的队列将任务 1 取出来任务 2fork任务 1join任务 2join之前的线程等待的时候会取帮助其他线程的任务
JDK 19 的虚拟线程也是基于ForkJoinPool
## ForkJoinPool的底层核心原理源码解析
## JDK19中虚拟线程基于ForkJoinPool的相关实现
## 如何理解 volatile 关键字
volatile 关键字用于避免指令重排序,同时保证共享变量在内存中的可见性,底层是使用内存屏障来实现的
## CountDownLatch 和 Semaphore 的区别和底层原理
countDownLatch 为控制线程等待,让一个线程等待倒计时结束后执行,通过 countDownLatch. awit 方法阻塞,直到为 0 后继续
semaphore让线程通过 acquire 获取许可,获取不到被阻塞,通过 release 方法后返回许可
cycilcBarrier当线程达到屏障时等待一组线程
## ReentrantLock中的公平锁和非公平锁的底层实现
公平锁,去 AQS 排队获取锁
非公平锁,竞争锁,没有得到锁就去排队
这两种锁都是可重入锁,默认为非公平锁
## sleep、wait、join、yield
- 锁池
竞争锁的线程都会放入锁池中等待锁
- 等待池
调用 wait 方法会放入等待池中, 不会去竞争锁,只有 notify() 随机或 notifyAll () 会将所有线程放入锁池中
sleep 是 Thread 的静态方法wait 是 object 方法
sleep 不会释放锁,释放 CPU 执行权会冻结锁wait 会释放锁,加入到等待队列中
sleep 不依赖 synchornizedwait 依赖 synchornized
sleep 不需要被唤醒wait 需要
sleep 用于线程休眠或轮询暂停操作wait 用于线程间通信
sleep 会让出 CPU 执行时间并强制上下文切换wait 不一定wait 后可能还是会有机会竞争到锁重新执行
yield 执行后线程进入就绪状态,释放了 cpu 执行权,但是保留了执行资格,还是可能下次线程调度继续执行
join 执行后线程阻塞,直到其他线程结束或中断线程
## Sychronized的偏向锁、轻量级锁、重量级锁
首先是无锁,然后当有线程获取锁的时候,会在对象头中记录下线程的 id后面该线程来获取该锁的时候会直接获取锁当有线程竞争之后该锁升级成为轻量级锁轻量级锁为自旋锁自旋锁通过 CAS 获取预期的一个标记不会阻塞线程,当自旋过多时升级为重量级锁,重量级锁会阻塞线程
全局安全点执行清理任务的时候会尝试触发降级锁
## ThreadLocal 的底层原理
ThreadLocal 可以将数据缓存在一个线程内,每一个 Thread 对象都有一个 ThreadLocalMap这个 Map 里面 key 为对应的 ThreadLocal值为设置的缓存值读取的时候以该 ThreadLocal 为引用,在自己的 map 里找对应的 key
## ThreadLocal的原理的使用场景
数据库连接池session 会话管理
连接管理,一个线程持有一个连接,该连接对象不在线程间共享
对象跨层传输时,避免多次传递
线程间数据隔离
事务操作时,存储线程事务信息
## ThreadLocal[[内存泄露]]问题,如何避免
线程和 ThreadLocalMap 是强引用Map 和 ThreadLocal 的 Entity 也是强引用Entry 的 key 是 ThreadLocal 对象,是一个[[弱引用]],没有指向 key 的强引用该 ThreadLocal 就会被垃圾回收器回收,使用完成之后线程没有回收,但是 Entry 中的 value 是强引用不会被回收只有线程结束才会回收value 对象过多的时候就会导致内存泄漏,但是只要调用 get 或 set 方法就可以清理掉需要使用之后手动调用 remove 方法来清除该值
## 阿里一面:如何查看线程死锁
## 阿里一面:线程之间如何进行通讯的
## 并发、并行、串行
## 并发篇1
## 并发篇2-1
## 并发篇2-2
## 并发篇3
## 并发4
## 并发5
## 并发三大特性
## 对线程安全的理解
## 京东一面Java死锁如何避免
## 京东一面:如果你提交任务时,线程池队列已满,这时会发生什么
## 蚂蚁一面sychronized的自旋锁、偏向锁、轻量级锁、重量级锁分别介绍和联系
## 说说你对守护线程的理解
## 为什么使用线程池,参数解释
## 线程的生命周期及状态
## 线程池线程复用的原理
## 线程池的底层工作原理