首先要搞清楚线程与进程的区别:
进程就是在内存中正在运行的程序,比如电脑上正在运行的某个软件;而线程指的是进程中的一个最小执行单元。一个进程最少得有一个线程,就比如该软件中的某个具体的功能。
线程的创建方式:
1、继承Thread类;
2、实现Runable接口;
1、继承Thread类和实现Runnable接口,有什么区别?你一般选择哪个?为什么?
首先,java只能单继承,因此如果是采用继承Thread的方法,那么在以后进行代码重构的时候可能会遇到问题,因为你无法继承别的类了。
其次,如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
3、实现Callable接口;
1、实现Runable接口和实现Callable接口有什么区别?
实现Runable接口没有返回值,实现Callable接口有返回值。
4、线程池:
1、核心参数:核心线程数、最大线程数、阻塞队列、线程保活时间、临时线程保活时间单位、线程工厂、拒绝策略(
4种拒绝策略:
AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 (默认);
DiscardPolicy:丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃;
DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务;
CallerRunsPolicy:由调用线程处理该任务;
);
2、你一般是怎么来设置这些参数?
具体是根据实际业务场景来的;
3、线程池创建了,里面有线程吗?
没有,当有任务提交过来,才会创建线程去执行;
4、如果到达了最大线程数,请问,这个核心线程是多少?
核心线程数就是最大线程数。
5、介绍一下线程池的工作流程:
1、首先,当有任务提交时,判断是否到达核心线程数量?没达到,创建一个工作线程来执行任务;
2、工作队列是否已满?没满,则将新提交的任务储存在工作队列里;
3、是否达到线程池最大数量?没达到,则创建一个新的工作线程来执行任务;
4、最后,执行拒绝策略来处理这个任务。
线程状态:
新建、就绪、运行、阻塞、死亡
线程安全问题:
共享数据不安全,解决方案:锁
锁
Synchronized 与 Lock 的区别?
Synchronized:JVM层面、是关键字;出异常时会释放锁,不会出现死锁;不会手动释放锁,只能等同步代码块或方法结束后释放锁。
Lock:API层面、是接口;出异常时不会释放锁,会出现死锁,需要在finally中手动释放锁;可以调用api手动释放锁。
Synchronized使用方式:普通同步方法,锁是当前实例对象 this;
静态同步方法,锁是当前类的class对象;
同步代码块,锁是括号里面的对象【必须共享】,javap命令中是使用 monitorenter 和 monitorexit 指令实现的。
锁分类:
1、悲观锁与乐观锁
悲观锁:Synchronized;Lock;数据库的行锁、表锁
乐观锁:cas,就是比较和交换;数据库使用version字段
2、公平锁与非公平锁
公平锁:按线程顺序获得锁
非公平锁:线程随机获得锁
死锁:
死锁产生的原因
1、系统资源不足;
2、进程运行推进的次序不合适;
3、资源分配不当。
4、如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
死锁产生的原因及四个必要条件
1、互斥条件:一个资源一次只能被一个进程访问。
2、请求与保持: 一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3、不可剥夺:进程已获得的资源,在未使用完之前,不得强行剥夺。
4、循环等待:若干进程之间形成一种头尾相接的循环等待资源关系
线程通信
1、同步通信
wait、notify、notifyAll;
jion方法;
通过 volatile 关键字。
2、异步通信
消息中间件。
3、进程间的通信
http、feign;
socket;
mq。
多线程并发
线程安全的特性
原子性:一个线程操作是不能被其他线程打断
有序性:线程在执行程序是有序的
可见性:一个线程修改数据后,对其他线程是可见的
volatile
1、保证可见性,可以在一个线程修改了共享数据时对其他线程可见,其原理就是修改了变量副本值后及时同步到主内存,其他线程从主内存中获取。
2、保证有序性,会禁止指令重排
指令重排:Java代码翻译成class文件后,最终在JVM执行时,是把class翻译一个个的指令进行执行的。而CPU为了程序的执行性能,会对指令进行重新排序;
也就是说万一翻译后的指令是123,那么重排后的指令可能就是213。在多线程情况下,就会出现变量的可见性问题。
3、是基于内存屏障来保证
有序性:内存屏障(也称内存栅栏,内存栅障,屏障指令等,是一类同步屏障指令,是CPU或编译器在对内存随机访问的操作中的一个同步点,使得此点之前的所有读写操作都执行后才可以开始执行此点之后的操作),避免代码重排序;内存屏障提供了避免重排序的功能。
可见性:内存屏障之前的所有写操作都要回写到主内存,内存屏障之后的所有读操作都能获得内存屏障之前的所有写操作的最新结果(实现了可见性);内存屏障会把线程把工作内存中改变后的数据直接刷回主内存。其他线程就可以从主内存中获取最新数据。、
单例模式
一个应用中,该实例有且只有一个;
双重校验锁:
Spring集成线程池
@Async标记在方法上, 表示当前方法是异步执行的;
@EnableAsync加在启动类上,表示开启多线程异步。