1、创建线程有哪几种方式?谈谈你对多线程的理解?你平时如何使用多线程,有哪些注意事项?
- 创建线程分为三种方式:1、继承Thread类,2、实现Runnable接口,3、实现Callable接口。
- 但是在实际项目开发过程中,我一般是使用spring自带的ThreadPoolTaskExecutor类去创建线程池。
- 根据项目业务,创建一个多线程池配置类,如工单-工单流转业务。配置类加上@Configuration和@EnableAsync注解,方法线程池同步bean注解返回TaskExecutor对象。
2、线程池核心参数解析
- 核心线程数:线程池中保持活跃状态的最小线程数量,线程空置也不会消亡。
- 最大线程数:线程池最大线程数量,核心线程数满,等待队列满,扩大到最大线程数。
- 线程池空闲时间:当前线程数大于核心线程数,到达空闲时间,线程数恢复到核心线程数。
- 默认线程名称:线程名称
- 是否允许后台运行:一般设置为允许
- 拒绝策略:大部分情况下使用,调用者线程执行,如果有特殊业务,特殊处理。 AbortPolicy(默认):抛出RejectedExecutionException异常。 CallerRunsPolicy:直接在调用者的线程中运行该任务。 DiscardOldestPolicy:丢弃队列中最旧的任务,然后尝试重新提交当前任务。 DiscardPolicy:直接丢弃新提交的任务
3、线程池等待队列有哪几种,各种的应用场景。
ArrayBlockingQueue:
基于数组实现的有界阻塞队列。
创建时需要指定容量,一旦创建就不能改变。
可选公平性策略,默认是非公平的。
LinkedBlockingQueue:
基于链表实现的可选有界或无界的阻塞队列。
如果构造时不指定容量,则默认为无界队列。
支持高并发环境下的高效插入和删除操作。
PriorityBlockingQueue:
一个无界的优先级阻塞队列。
元素按照它们的自然顺序或者通过Comparator提供的顺序进行排序。
不保证同优先级元素之间的FIFO顺序。
DelayQueue:
无界的延迟阻塞队列。
队列中的元素只有当其指定的延迟期过后才能被取走。
元素必须实现Delayed接口。
SynchronousQueue:
一种特殊的阻塞队列,每个插入操作都必须等待另一个线程对应的移除操作。
实际上并不存储任何元素。
对于每一个put()操作都需要有一个匹配的take()操作。
LinkedTransferQueue:
基于链表的无界阻塞队列。
提供了tryTransfer方法,可以尝试立即传递一个元素给消费者,如果没有消费者则将元素放入队列。
LinkedBlockingDeque:
一个由链表结构组成的双向阻塞队列。
支持两端插入和移除元素。
可以设置容量限制或作为无界队列使用。
4、spring自带的ThreadPoolTaskExecutor类使用的什么队列?
ThreadPoolTaskExecutor默认使用LinkedBlockingQueue作为任务队列。无界队列,最大值为integer.max(2^32-1)21亿左右。
5、核心线程数如何设置?
看所属的任务是io密集型还是cpu密集型。io密集型就是数量大,每个线程计算量少;cpu密集型就是计算量大,并发线程少。如果线程多,且计算量少,看此业务触发的频率,我们项目中,比如工单业务的消息推送可以异步执行的,核心线程数为5,最大线程数为15。消息推送需求解析查询配置用户等记录表,然后通过mq生产消息,进行发送。如果在某一段时间触发,则可以核心线程数为1,根据触发数据量设计空闲线程数。