1、基础知识
1.1.什么是并发编程
用编程语言写的一个可以让计算机在同一时间执行多个任务的程序
1.2.并发编程的优缺点
优点:
1.可以充分利用多核CPU
2.可以提高程序的运行速度或响应速度
缺点:
1.会有线程安全问题
2.会有上下文切换的时间片开销
3.死锁
1.3.守护线程跟用户线程有啥区别
守护线程是运行在后台,为其他线程提供服务
用户线程是运行在前台,执行业务任务
1.4.什么是线程死锁
两个或两个以上的线程由于竞争资源而造成的一种阻塞现象
举例:线程A持有资源1,去竞争资源2;同时线程B持有资源2去竞争资源1,这就造成了死锁
1.5.线程死锁的必要条件
1.互斥条件:一个资源只能被一个线程持有
2.请求与保持:线程请求一个资源未获取到而阻塞,不释放另外一个资源
3.不剥夺条件:线程未使用完的资源不会被剥夺
4.循环与等待:两个线程相互等待的过程
1.6.线程死锁的解决方案
解决死锁的方案就是破坏造成死锁必要条件的任意一个即可
1.互斥不可改变,排除
2.破坏请求与保持:一次性申请所有需要的资源
3.破坏不剥夺:获取新资源发生阻塞的时候可以主动释放已占有资源
4.破坏循环等待:可以考虑sleep一会,就破坏了循环等待
1.7.创建线程的几种方式
1.继承Thread类
2.实现Runnable接口(无返回值,void)
3.实现Callable接口(有返回值,使用FutureTask获取返回值)
4.使用Executor工具类创建线程池
1.8.说说线程的生命周期
1.新建:线程刚刚创建出来,如:new Thread();
2.可运行:【新建】状态的线程调用start()方法后,如:thread.start();
3.运行中:【可运行】状态的线程获取到了CPU的执行时间片
4.阻塞:【运行中】状态的线程放弃了对CPU的使用权
4.1.等待阻塞:调用了wait()方法,进入等待队列等待唤醒
4.2.同步阻塞:获取synchronized锁失败,进入锁池等待锁被释放
4.3.其他阻塞:调用sleep()方法,或其他线程加入,如:t2.join();需要等sleep到期或者t2线程执行完
5.销毁:线程执行完或发生异常后线程结束
1.9.如何确保三个线程顺序执行
1.使用join实现:join字面意思就是加入的意思
A、B、C三个线程
A、B(A.join)、C(B.join)
B.start(),C.start(),A.start()
启动后无论谁先拿到cpu执行时间都是先ABC的顺序
2.使用CountDownLatch:计数为0才能执行
创建三个LA(0),LB(1),LC(1)
A、B、C三个线程
A(LA.wait();线程A执行;LB.countDown());
B(LB.wait();线程A执行;LC.countDown());
C(LC.wait();线程A执行;LC.countDown());
启动后,首先LA为0所以线程A执行完,LB减少为0;
线程B可以执行,执行完,LC减少为0;
线程C可以执行
3.使用单线程线程池来执行
2、并发理论
2.1.为什么代码会重排序
为了提高性能,JVM会对代码进行重排序
遵循规则:
1.不改变单线程下的执行顺序(可能改变多线程的执行顺序)
2.不破坏数据的依赖关系
2.2.as-if-serial规则和happens-before规则的区别
as-if-serial:保证单线程的执行结果不被改变
指令重排序遵循这一规则
hap