关于原子类
AtomicStampedReference为什么能解决ABA问题
- 引入了版本号的概念,将A->B->A转变为了 A1->B1->A2
- CAS第二步比较时,由于A2不等于A1,返回了false。
关于线程
画出线程状态图
interrupt, isInterrupted, interrupted的区别
方法 | 说明 |
---|---|
interrupt | 仅仅是设置线程的中断状态,并不会真正中断一个线程 |
isInterrupted | 返回线程的中断状态,不清除标志位 |
interrupted | 返回线程的中断状态,并清除标志位 |
哪些方法会处理中断状态
阻塞库方法如wait(),sleep(),join()在阻塞时一直检查中断状态,若检测到标志位置为true,则抛出InterruptedException,并清除中断状态。
wait,yield,sleep,join的区别
方法名 | 执行后线程状态 | 释放CPU资源 | 释放锁 | 其他 |
---|---|---|---|---|
sleep | 堵塞 | 是 | 否 | 给其他线程运行机会时不考虑线程的优先级 |
wait | 堵塞 | 是 | 是 | 必须在 synchronized 修饰的代码块中使用 |
yield | 就绪 | 释放 | 否 | 只能使同优先级或更高优先级的线程有执行的机会 |
join | 堵塞 | 是 | 否 | 等待异步线程执行完结果之后才能继续运行 |
Callable、Runnable的异同
- Callable可以获得返回值,Runnable没有
- Callable可以抛出异常,Runnable需要通过setDefaultUncaughtExceptionHandler()方法实现
RecursiveTask和RecursiveAction
- 都继承与ForkJoinTask,RecursiveTask有返回值,RecursiveAction无返回值
如何理解CompletableFuture
- 实现了Future,是个让Runnable任务返回结果的有用工具。
如何理解FutureTask
- 既实现了Runnable、也实现了Future,既是线程任务也是一个线程返回结果
关于线程池
画出线程池的状态图
线程池接收新的任务的处理流程
- 线程数小于核心线程数时,创建新线程;
- 缓存队列未满时,加入缓存队列;
- 缓存队列满时,创建新线程;
- 缓存队列满且线程已经达到最大线程数时,执行拒绝策略;
线程池的数据模型
- ctl前3位表示状态,后29位表示线程数
-
HashSet<Worker> workers
工作线程
线程池工作线程的数据模型
- Worker实现了Runable且持有Runnable属性
- 线程池在用户定义的任务上封装了一层,当线程thread启动时,会调用Worker的run()方法,内部执行用户定义的任务。
Executors类提供的线程池比较
| 线程池 | 实际线程池类 |说明 | 核心线程数| 最大线程数| 空闲存活时间| 任务队列 |
| newCachedThreadPool | ThreadPoolExecutor | 缓存线程池 | 0 | 无限 | 60秒 | SynchronousQueue |
| newFixedThreadPool | ThreadPoolExecutor | 固定线程池 | n | n | 0 | LinkedBlockingQueue |
| newScheduledThreadPool | ThreadPoolExecutor | 定时线程池 | n | 无限 | 0 | DelayedWorkQueue |
| newSingleThreadExecutor | ThreadPoolExecutor | 串行线程池 | 1 | 1 | 0 | LinkedBlockingQueue |
| newWorkStealingPool | ForkJoinPool | Fork-Join线程池 | cpu数 | - | - | WorkQueue |
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务 ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
四种拒绝策略
- AbortPolicy:丢弃任务,并抛出异常
- DiscardPolicy:丢弃任务,不抛出异常
- DiscardOldestPolicy:丢弃最早的任务,
- CallerRunsPolicy:直接在添加任务的线程执行。
ForkJoinPool 的原理
- 分而治之的思想,内部使用“工作窃取”算法,让任务在各个CPU上尽可能均衡
- 每个工作线程都有自己的工作队列
- 工作队列为线程私有的双端队列
- fork的子任务,将放入运行该任务的工作线程的队头,以LIFO的顺序来处理工作队列中的任务
- 空闲线程会从其他线程的队列尾部窃取任务
关于ThreadLocal
ThreadLocal 原理
- 获取当前线程的ThreadLocalMap属性
- ThreadLocal对象作为key,从ThreadLocalMap获取值
ThreadLocalMap 的 key 为什么是 weakReference 弱引用类型
- 当 key 没有 threadLocal 强引用时,GC 时就能够被回收
- 虽然key会被回收但是value不会被回收,当下一次调用ThreadLocalMap的方式时,它会主动删除key为null的Entry
- 综上,设计成弱引用类型只是多了一层保障,并不能完全避免内存泄露
关于InheritableThreadLocal
- thread类中有InheritableThreadLocalMap属性,用于存放父线程的本地线程变量
- 主要用于解决父子线程的本地线程变量的继承问题
关于TransmittableThreadLocal(TTL)
- 封装了一个线程池
- 当该线程池调用execute方法时,自定义的线程任务+TransmittableThreadLocal和对应的线程变量一起封装成新的线程任务
- 当该线程池中线程执行该线程任务时,先取出其中封装的本地线程变量加入到该线程的InheritableThreadLocalMap中。
- 能够解决线程池中线程继承添加任务线程的线程本地变量的问题
ThreadLocalMap关键知识点
- hash冲突时,采用的是线性探测法,试探i+1个槽位是否可以存放
- ThreadLocal需要显性调用remove,一方面避免内存泄漏,另一方面由于线程大多数都是共用的,容易导致数据错乱
- key 为什么是 weakReference 弱引用类型,当没有 threadLocal 强引用时,第一次GC 就能够被回收