ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Java面试并发编程,这8个知识点必须会

Java面试并发编程,这8个知识点必须会 线程的生命周期不止六种状态新建、就绪、运行、阻塞、等待、超时等待、终止Java里线程状态定义在Thread.State枚举中。面试官常问sleep和wait有什么区别sleep不释放锁wait释放锁并进入等待池需要notify唤醒。yield让出CPU但不释放锁join等待目标线程终止。线程状态转换是并发编程的地基地基不稳上层建筑全是空中楼阁。画得出状态流转图才说明你真理解线程调度。synchronized的锁升级从偏向到重量JDK 1.6之前synchronized是重量级锁直接找操作系统要互斥量。之后引入了偏向锁、轻量级锁、重量级锁的升级路径。偏向锁针对同一个线程反复进入同步块轻量级锁用CAS自旋避免阻塞自旋失败才膨胀成重量级锁。锁升级的本质是用空间换时间能用用户态解决的事绝不进内核态。面试时能说清楚对象头Mark Word的锁标志位变化基本就稳了。volatile的两层语义可见性与有序性volatile保证一个线程改了变量其他线程立刻可见。底层靠内存屏障写操作后插入Store屏障读操作前插入Load屏障强制刷回主内存并从主内存加载。它还禁止指令重排序单例模式的双重检查锁必须加volatile否则可能拿到半初始化对象。volatile不保证原子性i这种复合操作它管不了。把volatile当万能药的人迟早被线上bug教做人。CAS与原子类无锁编程的基石CAS全称Compare And Swap比较内存值和预期值相等才更新。AtomicInteger的incrementAndGet就是循环CAS直到成功。优点是无锁没有线程阻塞和唤醒开销。缺点有三个ABA问题、循环时间长开销大、只能保证一个变量原子性。ABA用版本号解决AtomicStampedReference就是干这个的。CAS是乐观锁的底层实现但乐观不代表盲目该悲观时还得悲观。AQS并发包里的万能框架AbstractQueuedSynchronizer是ReentrantLock、CountDownLatch、Semaphore的底层引擎。核心是一个volatile的state变量加一个CLH双向队列。获取锁失败的线程封装成Node节点入队前驱节点释放锁后唤醒后继节点。AQS把同步状态管理和线程排队抽象成模板方法子类只需实现tryAcquire和tryRelease。面试问ReentrantLock公平锁和非公平锁的区别答案就在AQS的入队时机上。线程池的七个参数一个都不能少核心线程数、最大线程数、空闲存活时间、时间单位、工作队列、线程工厂、拒绝策略。任务提交后核心线程满则入队队列满则扩到最大线程数再满则触发拒绝策略。无界队列会让最大线程数形同虚设任务无限堆积最终OOM。生产环境用有界队列拒绝策略选CallerRunsPolicy或自定义记录日志。线程池大小不是拍脑袋CPU密集型和IO密集型各有公式。ConcurrentHashMap并发容器的标杆JDK 1.7用分段锁把哈希表分成16个Segment每个Segment独立加锁。JDK 1.8改成CAS加synchronized锁单个桶锁粒度更细。扩容时多线程协助迁移sizeCtl变量控制初始化和扩容状态。ConcurrentHashMap不允许null键值因为无法区分“没有”和“值为null”。面试问它和HashTable的区别答“一个锁桶一个锁全表”只是及格能讲清楚扩容时的协助机制才算优秀。死锁的四个条件与排查手段互斥、持有并等待、不可剥夺、循环等待四个条件同时满足才会死锁。破坏任何一个就能预防加锁顺序统一、用tryLock设置超时、资源一次性申请。排查用jstack抓线程栈搜“deadlock”关键字或者用JConsole的检测死锁按钮。死锁不可怕可怕的是线上出了死锁你还不知道等用户投诉才去重启。代码里少用嵌套锁能不用就不用。并发编程的面试题背答案只能撑十分钟追问两层就露馅。真正理解这些知识点的前提是写过并发代码踩过线程安全的坑调过死锁和内存泄漏。八個知识点是一张网织密了高薪offer才兜得住。别等到面试被问倒才后悔当初只背了八股文。
返回列表