多线程
1.谈谈进程和线程的区别?
- 进程是系统进行资源分配和调度的独立单位,每一个进程都有它自己的内存空间和系统资源。进程实现多处理环境下的进程调度,分派,切换时,都需要花费较大的时间和空间开销。为了提高系统的执行效率,减少处理机的空转时间和调度切换的时间,以及便于系统管理,所以有了线程,线程取代了进程调度的基本功能。
- 简单来说,进程作为资源分配的基本单位,线程作为资源调度的基本单位。
2.那我们为什么要用多线程?在平时工作中用的多吗?
- 使用多线程最主要的原因是提高系统的资源利用率。现在cpu基本都是多核的,如果你只用单线程,那就是只用到了一个核心,其他的核心,就相当于空闲在那里了。
- 在平时的工作中多线程是随时可见的。比如说:我们系统web服务器用的是tomcat,tomcat处理每一个请求都会从线程池里边用一个线程去处理。又比如说:我们用连接数据库会用对应的连接池,比如Druid/C3P0/DBCP等等,这些都用了多线程的,
- 除了上面这些框架已经帮我们屏蔽掉手写多线程的问题,在我本身的系统也会用到多线程的。比如说:现在要跑一个定时任务,该任务的链路执行时间和过程都非常长,我们这边就用一个线程池将该定时任务的请求进行处理,这样做的好处就是可以及时返回结果给调用方,能够提高系统的吞吐量
public void push(PushParam pushParam){
try{
pushServiceThreadExecutor.submit(()->{
handler(pushParam);
});
}catch (Exception e){
logger.error("pushServiceThreadExector error, exception{}:", e);
}
}
- 还有就是我的系统中用了很多生产者与消费者模式,会用多个线程去消费队列的消息,来提高并发度。
3.什么是串行和并行?
- 所谓串行其实是相对于单条线程来执行多个任务来说的,我们就拿下载文件来举个例子,我们下载多个文件,在串行中它是按照一定的顺序去进行下载的,也就是说必须等下载完A之后,才能开始下载B,他们在时间上是不可能发生重叠的。
- 所谓并行就是当你下载多个文件,开启多条线程,多个文件同时开始下载,这里是严格意义上的同一时刻发生的,并行在时间上是重叠的。
4.什么是线程安全?
5.解决线程安全问题的思路?
- 能不能保证操作的原子性,考虑atomic包下的类够不够我们使用
- 能不能保证操作的可见性,考虑volatile关键字够不够我们使用
- 如果涉及到对线程的控制(比如一次能使用多少个线程,当前线程触发的条件是否依赖其他线程的结果),考虑CountDownLatch/Semaphore等等
- 如果是集合的话,考虑java.util.concurrent包下的集合类
- 如果是synchronized无法满足,考虑lock包下的类(synchronized虽然牛逼,但是无脑使用的话会影响程序的性能)
- …
6.什么是死锁?
- 当前线程拥有其他线程需要的资源,当前线程等待其他线程已拥有的资源,双方都不放弃自己所拥有的资源,就会产生死锁。
- 避免死锁的方式一般有:
- 固定加锁的顺序,比如我们可以使用Hash值得大小来确定加锁的先后
- 尽可能缩减加锁的范围,等到操作共享变量的时候才加锁
- 使用可释放的定时锁(一段时间申请不到锁的权限了,直接释放掉)