1.CAS是什么,存在什么问题?
CAS是一种无锁化并发管理编程,执行流程是先读取内存中的值A,计算得出B,在将自己读取的值A于内存中的值C比较,若一样,则直接更新数据,若不一样则重试或自旋。
问题:ABA问题,例如线程A读取内存中的值为A=15,存在线程B将内存中的值从15修改到10,再修改为15,线程A比较发现没有被修改,直接更新,线程A并没有发现线程B修改了。可以通过加入版本号来判断是否被修改。
2.原子性,可见性?
原子性是指最小的执行操作,CAS的操作是具有原子性,但CAS线程间不存在可见性,可以通过关键字volatile关键字实现可见性。
3.HashMap底层,索引如何查找,为什么使用链表,红黑树的优势?
HashMap底层是数据结构是哈希表+链表+红黑树,索引通过与存储相同的哈希算法计算得出哈希表的下标,找到key。链表是为了解决哈希冲突,链表过长(链表长度大于8)会转变为红黑树,红黑树搜索效率比长链表高,性能更好。
4.HashMap的两个参数?
key-value键值对,key值不能重复,唯一,value可以重复,可以通过key值查找value。
5.什么时候触发重gc?
younggc晋升失败,Minor GC之后,存活对象晋升到老年代,老年代空间放不下,元空间Metaspace达到gc阈值; 代码手动调用 System.gc();堆内存分配失败;老年代空间分配担保失败。
6.如何判断对象是无用的?
gc垃圾收集器捅过,引用计数算法:在对象内部设置一个引用计数器,有多少引用,计数就为多少,为0,代表该对象无用,可达性分析算法:给一个根对象为gcroots,若没有与gcroots关联的对象,为无用对象。
7.volatile关键字,底层如何实现?
底层java通过内存屏障,更加轻量化,当java写入时volatile关键字会强制刷新工作内存到主内存中,保证与其他线程的可见性,读取时会强制将主内存中的内容刷新到当前工作内存,也可以保证指令重排。
8.锁的实现方式?
锁有synchronize锁,Lock类得实现类ReentrantLock,ReentrantReadWriteLock,CAS。
9.ThreadLocal底层实现?
ThreadLocal是为线程存储局部变量,与其他线程隔离,底层是通过ThreadLocalMap实现,内部是一个Entry类型的数组,每个Entry的的key为该ThreadLocal对象,值value为存储的数据。
10.synchronize实现?
synchronize是关键字,声明在方法上,或写在代码块中,1.8之后实现了锁升级,由无锁->偏向锁->轻量级锁->重量级锁,没有线程时,处于无锁状态,当锁发现只存在一个线程,升级为偏向锁,判断只要是这个线程,便直接执行,不用再频繁获取锁,发现不同的线程时,升级为轻量级锁,通过CAS的方式获取锁,若并发激烈,升级为重量级锁,此时通过独占的方式持有锁,其他线程处于阻塞状态,互斥,拍他的特点。
11.JVM内存?
JVM内存分为线程共享和线程私有
线程共享:堆,元空间
线程私有:虚拟机栈,本地方法栈,程序计数器
12.Gc原理,GC怎么判断需要被回收??
GC就是自动垃圾回收,JVM找出堆中不再被引用的对象,释放它占用的内存,避免手动释放内存、防止内存泄漏。
gc垃圾收集器通过,引用计数算法:在对象内部设置一个引用计数器,有多少引用,计数就为多少,为0,代表该对象无用,需要回收,可达性分析算法:给一个根对象为gcroots,若没有与gcroots关联的对象,为无用对象,需要回收。
13.多线程?
多线程是在同一个进程内,并发执行多条独立执行路径。一个进程可以包含多个线程,线程共享进程的资源,但每个线程有自己独立的栈、程序计数器。
CPU 通过时间片轮转,让多个线程交替执行,宏观上看起来同时运行,用来提升资源利用率、提高程序效率。
14.线程状态?
线程新创建,未执行start()方法时,为NEW状态,在线程正在执行或正在执行,处于RUNNABLE,执行join(时间值),wait(时间值),sleep(时间值),等方法时,会进入计时等待状态(TIMED_WAITING),执行join(),wait()方法,会进入等待状态(WAITING)状态,需要通过notify(),notifyAll()等方法唤醒才能进入RUNNABLE状态,如存在竞争锁失败的线程会进入阻塞状态(Blocked),竞争成功到RUNAABLE状态,执行完run()方法,到线程终止状态(TERMINATED)。
15.线程池是怎么实现的?
线程池源码中通过一个clt的32位的整数类型,前三位保存了线程池的状态,后29位保存了工作线程数量,通过CAS原子性操作进行更新。可以通过创建ThreadPoolExecutor对象实现线程池,有ForkjoinPool,也可也通过Executors工具类创建线程池,核心参数有:核心线程数,最大线程数,非核心线程的空闲时间和时间单位,工作队列,线程工厂,拒绝策略,执行流程是当线程进入线程池,判断若小于核心线程数,直接创建线程执行若大于核心线程数,小于工作队列,入队等待核心线程执行完,再执行,若大于工作队列,小于最大线程数,则创建非核心线程数,执行线程任务,若大于最大线程数,则抛出拒绝策略。
16.如果队列满了怎么办,拒绝策略有哪些?
队列满了判断若小于最大线程数,则创建非核心线程数,执行线程任务,如果大于最大线程数则执行拒绝策略,拒绝策略有:Abortpolicy(默认拒绝策略),丢弃线程任务,并抛出异常,Discardpolicy,直接丢弃线程任务,Discardoldestpolicy,丢弃工作队列中最早的线程任务,并重新提交线程任务,callerrunspolicy,直接由提交线程任务的线程执行该线程任务。