问题11:Synchronized锁升级是什么?
无锁到偏向锁(当一个线程,首次访问同步带那块并获取锁时,会在对象头的Mark word中存入该线程ID,此时,锁的状态为偏向锁,偏向锁不会主动释放,只有当其他线程尝试竞争时才会撤销)
偏向锁到轻量级锁(当有另一个线程,尝试访问同一个代码块时,偏向锁会升级成轻量级锁CAS。CAS操作尝试获取锁,避免线程阻塞)
轻量级锁到重量级锁(同一时间存在多个线程竞争锁,轻量级锁会升级为重量级锁,此时线程会阻塞 性能开销大)
问题12:CAS的原理是什么?会遇到什么问题,怎么解决?
CAS(Compare and Swap比较并交换)是一种无锁化技术,他的原理首先读取原值A,计算新值B,然后比较需要读写的内存值c与原值A是否一致,如果一直则更新不一致则失败或者自旋。
CAS是CPU支持的一种对内存中的共享数据,进行操作的CPU指令,例如cmphxchg
底层是unsafe类提供的compareAndSwapXXX()等方法实现。
在操作过程中会遇到ABA问题也就是:
线程 P1在共享变量中读到值为A; 线程P1被抢占,线程P2开始执行; 线程P2把共享变量里的值从A改成了B,再改回到A; 线程P2被抢占,线程P1开始执行;
线程P1回来看到共享变量里的值没有被改变,于是继续执行;
可以通过 JDK 的Atomic 包中的 AtomicStampedReference 类来解决 ABA 问题:使用compareAndSet 方法的作用是首先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
问题13:线程安全的集合类有哪些?
1.Vector(通过synchronized同步锁保证线程安全)
2.CopyOnWriteArrayList(通过Reentrantlock实现线程安全)
3.ArrayBlockingQuene、LinkedBlockingQuene通过Reentrantlock实现线程安全
4.ConcurrentHashMap(通过CAS+synchronized实现线程安全)
5.Hashtable(通过synchronized实现线程安全)
问题14:线程池的核心参数和执行流程?
参数:
corePoolSize:核心线程数
maximumPoolSize:最大线程数
非核心线程空闲存活时间和时间单位
workQueue:工作队列
threadFactory:线程工厂
拒绝策略(Abortpolicy、Discardpolicy、DiscardOldestpolicy、CallerRunspolicy)
执行流程:
首先,提交线程任务。
判断当前“工作线程数”是否超出“核心线程数”。
- 若未超出:创建核心线程,执行线程任务;
若超出核心线程数,则判断工作队列是否已满:. 队列未满:线程任务放入工作队列,等待池内已有空闲线程主动取出任务执行;
队列已满:判断当前工作线程数是否超出最大线程数。 - 若未超出:创建非核心线程执行任务,并执行线程任务;- 若超出最大线程数:执行拒绝策略
问题15:内存有限,快速找到 top10000,怎么办?
小顶堆
维护一个大小为 10000 的小顶堆
遍历全部数据:
堆里面元素不足 10000:直接入堆
堆满了:当前元素 > 堆顶(堆里最小值)→ 弹出堆顶,把当前元素入堆;否则跳过
遍历结束,堆中就是最大的 10000 个元素
问题16: 数据量极大,找到一个数在其中是否存在,怎么做?
布隆过滤器:基于数组+多个哈希函数实现,用来判断一个元素是否一定不存在,或者可能存在。
问题17: 布隆过滤器的原理和优缺点是什么?
原理:
初始化一个全0的BitSet位数组
插入元素:经过k个不同哈希函数算出k个下标,把对应bit置为1(true)。查询元素:同样k个不同哈希函数算出看个下标,统计所有下标位置的值:只要有一个bit是(false),代表一定不存在;全部是1(true)大概率存在
优点:
占用内存极小,空间效率极高
插入、查询时间复杂度 O (k),速度快
缺点:
存在误判(假阳性)
判断存在,实际不一定存在
不能删除元素
不能获取集合里的真实元素,只能判断存在性
元素容量超过设计容量,误判容易飙升
问题18:如果让你实现布隆过滤器的 hash 算法,怎么写?
利用 bitSet 作为位图,维护 k 个独立哈希函数。添加元素时,通过 k 个哈希得到多个下标,将对应 bit 置 1;查询时校验全部对应 bit 位,存在 0 则一定不存在,全 1 则可能存在。
代码实现:





