目录
2.1sychronized关键在的底层原理 (底层实现依赖Monitor)
2.1.1 对象在hotspot(堆的实现)中存在 下面的两个图,用来表明对象怎么和锁关联上的
2.3 CAS知道吗? (compare and swap)
4.1 线程池的使用(countdownlauch,future)
1. 线程基础知识
1.1 进程线程
- 进程是正在运行程序实例,进程包含了线程,每个线程执行不同任务.
- 不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间.
- 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低
1.2 并行,并发
现在都是多核CPU,在多核CPU下
- 并发是同一时间应对多件事情的能力,多个线程轮流使用一个或多个CPU.
- 并行是同一时间动手做多件事的能力,4核CPU同时执行4个线程.
1.3 创建线程的方法?
1.3.1 方法
- 继承Thread类
- 实现runnable接口
- 实现Callable接口
- 线程池创建线程(项目中使用方式)
1.3.2 runnable和callble区别
- runnable接口run方法没有返回值.
- callable接口call方法有返回值,需要FutureTask获取结果.
- callable接口的call()方法允许抛出异常,而runnable接口run()方法的异常只能内部消化,不能继续上抛
1.3.3 run()和start()有什么区别?
- start():用来启动线程,通过该线程调用用run方法执行run方法中所定义的逻辑代码,start方法只能被调用一次
- run() :封装了要被线程执行的代码,可以调用多次.
- run():方法只是一个普通方法,调用它并不会创建新线程,只是在当前线程中执行。
- start():方法用于启动一个新线程,并在新线程中执行
run()
方法中的逻辑。
1.3.4 函数式接口
函数式接口 : 类中只有一个抽象方法 ,可以存在默认方法 即default修饰的方法 (不是只能由抽象方法存在了)
比如 线程 Thread thread = ()->{system.out.print("1")} .他就知道实现了那个方法,多个抽象方法就不行了
1.4 线程包含的状态,状态之间的切换
1.2.1 线程包括哪些状态?
NEW(新建状态):当线程对象被创建但还没有调用
start()
方法时,线程处于新建状态。RUNNABLE(可运行/运行状态):线程调用
start()
方法后,线程进入可运行状态。在可运行状态下,线程可能正在执行,也可能等待操作系统分配执行时间。BLOCKED(阻塞状态):线程被阻塞等待一个监视器锁,例如在
synchronized
块中调用了wait()
方法,线程将进入阻塞状态。WAITING(等待状态):线程无限期地等待另一个线程执行特定操作,例如调用
Object.wait()
方法或Thread.join()
方法,使线程进入等待状态。TIMED_WAITING(计时等待状态):线程等待另一个线程执行特定操作,但等待一段时间后会自动返回,例如调用
Thread.sleep()
方法或Object.wait(timeout)
方法。TERMINATED(终止状态):线程执行完
run()
方法中的代码或者因为异常退出后,线程进入终止状态。
1.4.2 线程状态之间如何变化的?
- 创建线程对象是新建状态
- 调用了start方法装变为可执行状态
- 线程获取到CPU执行权,执行结束是终止状态.
- 在可执行状态过程中,如果没有获取CPU的执行权,可能会切换其他状态
1. 如果没有获取锁(synchronized或lock)进入阻塞状态,获取后切换为可执行
2.如果线程调用了wait()方法进入等待状态,其他线程调用notify()唤醒后可切换为可执行状态
3. 如果调用了sleep()方法,进入计时等待状态,到时间后可以切换为可执行
1.4.3 notify 和notifyall
notify():
notify()
方法用于唤醒在对象监视器上等待的单个线程。如果有多个线程在对象监视器上等待,系统会随机选择其中一个线程唤醒,使其从等待状态变为就绪状态。- 被唤醒的线程会尝试重新获取对象的锁,一旦成功获取锁,它就可以继续执行。
notifyAll():
notifyAll()
方法用于唤醒在对象监视器上等待的所有线程。所有等待在对象监视器上的线程都会被唤醒,从等待状态变为就绪状态。- 然后,这些线程会竞争对象的锁,只有一个线程能够获取到锁并继续执行,其他线程会继续等待。
1.5 新建T1T2T3线程按顺序执行?
join实现就好
public class ThreadExecutionOrder {
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread(), "T1");
Thread t2 = new Thread(new MyThread(), "T2");
Thread t3 = new Thread(new MyThread(), "T3");
try {
// 启动线程T1
t1.start();
t1.join(); // 等待T1执行完毕
// 启动线程T2
t2.start();
t2.join(); // 等待T2执行完毕
// 启动线程T3
t3.start();
t3.join(); // 等待T3执行完毕
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class MyThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is running");
}
}
}
1.6 wait和sleep方法不同?
1.7 如何停止正在运行的线程?
三种方式:
- 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止.
- 使用stop方法强行终止(不推荐,已作废).
- 使用interrupt方法终端线程.
. 打断阻塞的线程(sleep,eait,join)的线程,线程抛出interrutedException异常
. 打断正常线程,可以根据打断状态来标记是否退出线程.
- 打断正常线程会修改currentthread.isinterrcepted的状态为true
1.8 启动线程为啥是start(),不是run()
run 方法直接调用就是在主线程直接执了 ,
start() 并不是单单一个方法, 会先创建一个线程 ,来执行run
1.9 守护线程
1.10 线程之间通通信方式
左侧第一种 ,间接通信 ,锁上了修改后,他线程能感知到
2. 锁
2.1sychronized关键在的底层原理 (底层实现依赖Monitor)
2.1.1 对象在hotspot(堆的实现)中存在 下面的两个图,用来表明对象怎么和锁关联上的
2.1.2 锁升级
Minotor重量级开销大,没有竞争的时候使用轻量锁,一旦有竞争就会升级为重量级的
2.2 JMM (java内存模型)
线程私有的内存+共享内存
2.3 CAS知道吗? (compare and swap)
体现了乐观锁的实现原理,不加锁,每次会用旧值和之前的比较,不一样重新获取执行直到相等,或者设置阈值,多少次不在比较
2.4 volatile 理解
因为jit优化了导致指令重排,直接禁止的话影响其他线程使用
2.5 AQS,是否公平锁?
2.6 ReentranLock实现原理?
多个线程抢资源保证原子性cas
- 公平非公平锁是体现在线程加锁的阶段 : 线程肯定有等待队列,非公平的不会来了就去队列排队,而是尝试获取锁,获取不到
- 就回去队列等待了. 公平锁来了就去排队
2.7 sychronized和lock区别?
2.8 死锁?
2.9 ConcurrentHashMap?
2.10 并发程序出现问题的原因?
3.线程池
3.1 核心线程池的参数?
3.2 线程池的执行原理
3.3 常见阻塞队列
使用的多的是linkedBlockingQueue,说我们项目是的这个,默认无界但是我们会给个界限
3.4 如何确定核心线程数(和Cpu有关)
3.5 线程池的种类
1.适用任务量已知,相对耗时的任务
2. 使用于顺序执行的线程
3. 适合任务数比较密集,每个任务执行短的情况
4.适合周期性的
3.6 为啥不建议使用Executor创建线程池
这个就是创建上面的线程池,因为默认的最大线程数是interger.maxvalue,可能会耗尽资源
3.7线程池的状态
4.使用场景
4.1 线程池的使用(countdownlauch,future)
4.2 countdownlauch的使用场景
countdownlauch用来等待子线程执行完成后在执行主线程,执行任务还是线程池,导入数据到es
4.3 用户下单
用户下单完后,查询信息,商品,物流,订单在三个微服务,如何完成?
顺序执行慢,所以多线程,用countdownlauch,等待都完成在返回就好了,但是需要 获取线程返回值,需要用callable
4.4 异步调用
@enableansy 启动类添加开启异步调用
@Ansy("")
4.5 控制方法并发访问的线程数量
4.6 threadlocal
threadlocal ,你只要实现了thread或者实现runable 都有threadlocalmap threadlocal的
使用场景 例如这个线程调用三个类的多个方法,只需要把用到的对象,放到threadlocal这样就不用再每个方法声明了,需要的时候只要threadlocalget就好了
不能set多次,会覆盖 ,
5.线上问题
5.1 多次下单
描述: 可能网络问题,导致多次点击,生成多个订单(占用内存,体验差)
原因:网络延迟,或者系统卡顿
解决:前端按钮置灰,后端使用redis的setnx,然后缓存token+url+商品id,设置几秒过期时间,(一般不会几秒内重复购买同一商品)