3.Java并发常见面试题总结

什么是线程和进程?

进程是系统资源调度的基本单位

线程是cpu资源调度分配的最小单位

一个进程有多个线程。

什么是用户线程、内核线程?区别是什么

说说线程的生命周期和状态?

NEW

RUNNABLE

BLOCKED

WAITING

TIME_WAITING

TERMINATED

什么是线程上下文切换?

什么是线程死锁?

循环等待、互斥、不剥夺、请求与保持

sleep() 方法和 wait() 方法对比?

让出资源

主动被动

(重要)可以直接调用 Thread 类的 run 方法吗?Start和run的区别?

同步、异步

JMM(Java 内存模型)详解

什么是JMM?

  • java内存模型
  • 规定了线程和内存之间的关系
  • 约定了一些保证线程安全的规范,比如happen before原则

java线程与主内存的关系

  • 线程内部有共享变量副本
  • 当线程需要通信时,使用共有空间,通过复制的形式共享

什么是指令重排序?特点是什么?

比如一个new运算/

  • 申请内存
  • 初始化值
  • 指向引用对象

只要保证语义一致即可。

happens-before 原则是什么?干嘛用的?

A HB B

就说明语义上A一定发生在B之前。

JMM规定了一些HB规则:

volatile的写 HB 读

解锁 HB 加锁

A HB B HB C -- A HB C

并发编程三大特性:(重要)

原子性、可见性、有序性

volatile

两个作用:

保证可见性、保证有序性

可见性,通过提前把内容写入主内存,且要求线程访问时都通过主内存访问,保证了可见性。

有序性,通过内存屏障,把loadload、loadstore等屏障添加在读和写的之前和之后,就可以保证volatile的写一定在读之前,保证了指令重排序

缺点:没有保证原子性

这一点可以用+锁实现

乐观锁和悲观锁

乐观锁:

假想每一次。。。

CAS,重试,不阻塞

缺点,写多时会性能不足

悲观锁:

假想每一次。。。

互斥,阻塞

死锁问题。

乐观锁的实现、问题、如何解决

synchronized

如何使用 synchronized?(重点)

  • 加载实例方法
  • 加载静态方法
  • 加在对象上

构造方法可以用 synchronized 修饰么?

synchronized 底层原理了解吗?

在被锁之前和之后添加monitor enter、exit监视器。

ACC_SYNCHRONIZED

对象的内存布局?

  • 对象头
    • markword
      • lock锁状态
      • biased_lock:偏向锁标志位
      • 轻量级锁标志位,指向线程id
      • 重量级锁标志位,指向monitor的指针
    • 类指针
  • 实例数据
  • 补齐填充

如何查看对象的内存布局及锁状态?

JOL:java object layout

锁优化

1、自旋优化

2、批量重偏向、批量撤销

3、锁粗化

(重点)synchronized 和 volatile 有什么区别?

二者经常一起配合使用,比如单例模式

锁升级

  • 无锁00
  • 偏向锁(mark word对象头中保存线程的id)01
  • 轻量级锁10
  • 重锁11

ReentrantLock是什么?4个特点?

也是一种锁机制,但是比synchronized更灵活。

共同点:

  • 排他锁
  • 可重入锁

不同点:

  • 可充式
  • 非公平和公平
  • 可以指定唤醒
  • 可中断

synchronized+wait+notify

reentrantLock+await+signal(condition)

什么是可重入锁?

比如某一个方法上加了锁,但是这个方法是递归的,那么当同一个线程再次获取同一个对象的时候,可以获取到,就叫做可重入锁。

ReentrantLock加锁的执行流程?

就是AQS的加锁过程

  • state,当前资源是否可用,如果不可用,还要判断当前资源是否为当前线程,如果是则可重入
  • 如果可用,则判断等待队列是否为空,如果为空,则当前线程CAS抢占。否则加入阻塞队列CLH

ReentrantLock释放锁的执行流程

判断占用的是否为当前线程,如果是则state-1

再判断state是否为0.

唤醒等待队列

lock和tryLock的区别?(重要)

lock会阻塞

tryLock不会阻塞,直接返回结果

ReentrantReadWriteLock

前16位是读锁、后16位是写锁

AQS原理。

# 说说CopyOnWriteArrayList

线程安全的List。

原理是:写时复制

缺点:一致性得不到保证

# 说说fail-fast与fail-safe

遍历过程中不可以被修改

遍历过程中可用修改

Automic原子类

基本类型源自类AutomicInteger

数组类型原子类AtomicIntegerArray

引用类型原子类AtomicReference

对象字段更新器AtomicIntegerFieldupdateer

优势

如果不用原子类,计算时需要volatile+锁,保证原子性,但是如果直接使用原子类,就可以更简单的实现原子性。

AQS

介绍AQS?

抽象队列同步器。

有两个重要组成部分:

共享资源状态量state

阻塞队列双向链表CLH

独占锁?

ReentrantLock、ReentrantReadLock

共享资源状态量state为0或1

共享锁?

1、semaphore

  1. 功能:允许一个资源有K个线程同时访问它
  2. 原理:state初始为K,每获取acquire一次-1. 释放release一次+1.当state==0时表示满了,之后的阻塞队列。

2、CountDownLatch

  1. 功能:保证多个线程阻塞到同一个地方,然后一起开始,比如ABCD四个任务同时全部执行完再执行E任务。
  2. 原理:state初始为K,每latch一次-1,主线程await阻塞等待,当state==0时,主线程被唤醒。
  3. 特点:一次性的,用完就没了

如何自己使用AQS

  1. 继承AQS
  2. 重写tryAcquire
    1. CASstate
    2. SetOwnerThread
  3. 重写tryRelease
    1. getState
    2. setState
    3. setOwnerThread

ThreadLocal

作用?

存储结构?

  • ThreadLocalMap:
  • 每个线程都有一个它对应的ThreadLocalMap放在线程本地内存。
  • 每个ThreadLocalMap中的键值对,key表示ThreadLocal、Val表示存入的实际值。

内存泄漏问题?

4种引用类型

虚:用队列接收对象死亡的通知。(实际开发几乎用不到)

Threadlocal的内存泄漏

1、原因

2、为什么不都是弱引用?

3、为什么不都是强引用?

ThreadLocalMap .set/get详解

1、hash算法计算key

2、解决冲突

  1. 如果key为空且val为空,则存入
  2. 如果key不空,则下一个找
  3. 如果key空val不空,则说明此槽位失效,发生探测式清理,然后更新当前槽位

清理分类

探测式清理

启发式清理

扩容机制

  • 如果执行完启发式清理工作后,未清理到任何数据,且当前散列数组中Entry的数量已经达到了列表的扩容阈值(len*2/3),就开始执行rehash()逻辑
  • 先从头到尾清理key=null的槽位(使用expungeStaleEntry的探测式清理方法)、清理完之后再通过判断size >= threshold - threshold / 4 也就是size >= threshold * 3/4 来决定是否扩容。
  • 扩容后的tab的大小为oldLen * 2。遍历老的散列表,重新计算hash位置,然后放到新的tab数组中。

线程池

为什么要用线程池?

  1. 避免线程资源的浪费,线程复用
  2. 减少线程创建过程,加快响应速度
  3. 方便管理

如何创建线程池?

Executor

4种内置线程池

Fixed

Single

Cached(可无限扩容的线程池)

Schedule(定时任务的线程池)

ThreadPoolExecutor

参数:核心线程数、最大线程数、阻塞队列、

饱和处理、KeepAliveTime、UNIT、Factory

执行流程
  1. 先看核心线程满没满,美满就使用核心线程
  2. 再看阻塞队列满没满,没满就加入阻塞队列
  3. 最后看最大线程数满没满,没满就新建不多于最大线程数的一个线程;满了就执行包和策略
饱和策略有哪些?
  1. 默认抛出异常,并抛弃饱和的任务(AbortPolicy)
  2. 直接丢弃饱和任务,什么也不做
  3. 使用主线程执行饱和任务
  4. 用最后一个等待的任务替换饱和任务(CallerRunPolicy)
常用阻塞队列?
  1. LinkedBlockingQueue:Fixed、Single,Cache
  2. ArrayBlockingQueue:不可扩容,不容易OOM,性能较差
  3. DelayedWorkQueue:Schedule
  4. Priority:自定义优先级的线程池

线程数量过大过小都有哪些问题?如何设定线程池的大小?(重要)

线程池数量过大:频繁的上下文切换

过小:CPU资源没有充分利用,且容易导致阻塞队列爆了

N+1:其中1表示防止线程偶发的缺页中断

2 * N或者 N + N * 线程等待时间 / 线程运行时间

线程池的五种状态

RUNNING

SHUTDOWN

STOP

TIDYING

TERMINATED

线程的5种状态

STARTED

RUNNING

WAITING

TIME_WAITING

TERMINATED

BLOCKING

合理关闭线程池?

ShutDown + AwaitTermination

Runnable vs Callable

execute() vs submit()

shutdown()VSshutdownNow()

isShutdown() VS isTerminated()

Future、Callable、FutureTask

Yield、Sleep、Wait、Notify对锁的影响?

# 如何优雅的中断线程

interrupt()

interrupted()

InterruptedExeception

线程的创建有哪几种?

  1. 继承Thread、、、
  2. 实现Callable、、、
  3. 线程池

Run()和Start()/execute()的区别

CPU核心数和线程数的关系

说说进程间的通信

  1. 管道 |
  2. 命名管道 >
  3. 消息队列
  4. 共享内存
  5. socket
相关推荐
晓1313几秒前
第七章 【C语言篇:文件】 文件全面解析
linux·c语言·开发语言
愚者游世几秒前
Delegating Constructor(委托构造函数)各版本异同
开发语言·c++·程序人生·面试·改行学it
一 乐1 分钟前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
KIKIiiiiiiii2 分钟前
微信个人号API二次开发中的解决经验
java·人工智能·python·微信
梵刹古音3 分钟前
【C语言】 指针基础与定义
c语言·开发语言·算法
80530单词突击赢3 分钟前
SpringBoot整合SpringMVC全解析
java·spring boot·后端
Ekehlaft6 分钟前
这款国产 AI,让 Python 小白也能玩转编程
开发语言·人工智能·python·ai·aipy
rit84324999 分钟前
MATLAB中Teager能量算子提取与解调信号的实现
开发语言·matlab
开源技术11 分钟前
Python GeoPandas基础知识:地图、投影和空间连接
开发语言·ide·python
vx1_Biye_Design13 分钟前
基于Spring Boot+Vue的学生管理系统设计与实现-计算机毕业设计源码46223
java·vue.js·spring boot·spring·eclipse·tomcat·maven