什么是线程和进程?
进程是系统资源调度的基本单位
线程是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的指针
- 类指针
- markword
- 实例数据
- 补齐填充
如何查看对象的内存布局及锁状态?
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
- 功能:允许一个资源有K个线程同时访问它
- 原理:state初始为K,每获取acquire一次-1. 释放release一次+1.当state==0时表示满了,之后的阻塞队列。
2、CountDownLatch
- 功能:保证多个线程阻塞到同一个地方,然后一起开始,比如ABCD四个任务同时全部执行完再执行E任务。
- 原理:state初始为K,每latch一次-1,主线程await阻塞等待,当state==0时,主线程被唤醒。
- 特点:一次性的,用完就没了
如何自己使用AQS
- 继承AQS
- 重写tryAcquire
- CASstate
- SetOwnerThread
- 重写tryRelease
- getState
- setState
- setOwnerThread
ThreadLocal
作用?
存储结构?
- ThreadLocalMap:
- 每个线程都有一个它对应的ThreadLocalMap放在线程本地内存。
- 每个ThreadLocalMap中的键值对,key表示ThreadLocal、Val表示存入的实际值。
内存泄漏问题?
4种引用类型
强
软
弱
虚:用队列接收对象死亡的通知。(实际开发几乎用不到)
Threadlocal的内存泄漏
1、原因
2、为什么不都是弱引用?
3、为什么不都是强引用?
ThreadLocalMap
.set/get详解
1、hash算法计算key
2、解决冲突
- 如果key为空且val为空,则存入
- 如果key不空,则下一个找
- 如果key空val不空,则说明此槽位失效,发生探测式清理,然后更新当前槽位
清理分类
探测式清理
启发式清理
扩容机制
- 如果执行完启发式清理工作后,未清理到任何数据,且当前散列数组中
Entry
的数量已经达到了列表的扩容阈值(len*2/3)
,就开始执行rehash()
逻辑 - 先从头到尾清理key=null的槽位(使用expungeStaleEntry的探测式清理方法)、清理完之后再通过判断
size >= threshold - threshold / 4
也就是size >= threshold * 3/4
来决定是否扩容。 - 扩容后的
tab
的大小为oldLen * 2
。遍历老的散列表,重新计算hash
位置,然后放到新的tab
数组中。
线程池
为什么要用线程池?
- 避免线程资源的浪费,线程复用
- 减少线程创建过程,加快响应速度
- 方便管理
如何创建线程池?
Executor
4种内置线程池
Fixed
Single
Cached(可无限扩容的线程池)
Schedule(定时任务的线程池)
ThreadPoolExecutor
参数:核心线程数、最大线程数、阻塞队列、
饱和处理、KeepAliveTime、UNIT、Factory
执行流程
- 先看核心线程满没满,美满就使用核心线程
- 再看阻塞队列满没满,没满就加入阻塞队列
- 最后看最大线程数满没满,没满就新建不多于最大线程数的一个线程;满了就执行包和策略
饱和策略有哪些?
- 默认抛出异常,并抛弃饱和的任务(AbortPolicy)
- 直接丢弃饱和任务,什么也不做
- 使用主线程执行饱和任务
- 用最后一个等待的任务替换饱和任务(CallerRunPolicy)
常用阻塞队列?
- LinkedBlockingQueue:Fixed、Single,Cache
- ArrayBlockingQueue:不可扩容,不容易OOM,性能较差
- DelayedWorkQueue:Schedule
- 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
线程的创建有哪几种?
- 继承Thread、、、
- 实现Callable、、、
- 线程池
Run()和Start()/execute()的区别
CPU核心数和线程数的关系
说说进程间的通信
- 管道 |
- 命名管道 >
- 消息队列
- 共享内存
- socket