千锋教育-做有情怀、有良心、有品质的职业教育机构

400-811-9990
手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

上海
  • 北京
  • 郑州
  • 武汉
  • 成都
  • 西安
  • 沈阳
  • 广州
  • 南京
  • 深圳
  • 大连
  • 青岛
  • 杭州
  • 重庆
当前位置:青岛千锋IT培训  >  技术干货  >  Java项目中到底该怎么使用线程池?

Java项目中到底该怎么使用线程池?

来源:千锋教育
发布人:qyf
时间: 2023-02-21 17:35:50

  一. 前言

  最近有不少小伙伴私聊老师,问我能不能讲讲项目中怎么使用线程池?所以,今天老师就给大家安排一下,满足粉丝们的要求,给大家讲一下之前我在项目中使用线程池的一些经验。

  二. 线程池简介

  我们想要在项目中使用线程池,就必须要知道线程池是啥、咋用?所以请各位先跟着老师学学关于线程池的基础知识吧。

  2.1 线程池

  我们先来看看《阿里巴巴Java开发规范》中对于线程池的使用规范,其中有如下要求:

1280X1280

  我们平时开发使用时,一般都是使用Java原生的线程池API,也就是ThreadPoolExecutor来创建线程。我们利用该API进行统一的线程管理,在使用时只需要调用添加任务即可。

  2.2 代码演示

  接下来就是一段线程池的使用代码演示,大家可以参考一下。

  @Test

  public void thread(){

  //池化技术 :1.复用率 2.有效控制 3.性能

  //原生线程池 7个参数

  /**

  * 使用原生线程池创建

  * 7个参数

  * 1.核心线程数

  * 2.最大线程数

  * 3.空闲时间

  * 4.空闲时间的时间单位

  * 5.阻塞队列 7种

  * 6.线程工厂

  * 7.拒绝策略 4种

  * 线程池工作原理:先核心线程-->再阻塞队列-->最大线程数-->拒绝策略*/

  ThreadPoolExecutor poolExecutor=new ThreadPoolExecutor(4,10,

  10, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10),

  Executors.defaultThreadFactory() ,

  new ThreadPoolExecutor.AbortPolicy());

  //设置是否回收核心线程

  poolExecutor.allowCoreThreadTimeOut(true);

  //线程池的线程预热

  poolExecutor.prestartAllCoreThreads();

  //添加任务

  poolExecutor.execute(()->{

  System.err.println("遇见老师说:线程池在处理任务");

  });

  }

  2.3 线程池的工作过程

  那么上述代码中的线程池,是怎么处理线程任务的呢?且来听老师给你唠唠,线程池接收到一个线程任务后,会经过如下步骤:

  如果发现线程池中有空闲线程,则直接执行该任务;

  如果没有空闲线程,且当前运行的线程数少于corePoolSize,则创建新的线程执行该任务;

  如果没有空闲线程,且当前的线程数等于corePoolSize,同时阻塞队列未满,则将任务入队列,而不添加新的线程;

  如果没有空闲线程,且阻塞队列已满,同时池中的线程数小于maximumPoolSize ,则创建新的线程执行任务;

  如果没有空闲线程,且阻塞队列已满,同时池中的线程数等于maximumPoolSize,则根据构造函数中的 handler 指定的策略来拒绝新的任务。

  以上就是关于线程池的一些基本常识。

  三. 项目中使用线程池

  言归正传,咱们再来说一下在项目中到底该如何使用线程池。老师之前给某个公司做过一个项目,其中有个业务,要满足大批量Excel格式的数据上传并导入到数据库中。老师本以为只是几百条数据,结果在对接时才发现,对方的数据量都是上万级别的批量数据导入。

  来吧,直接让你看看老师的实现代码。

  @Override

  public R uploadExcel(MultipartFile file) throws IOException {

  //1.获取上传的内容 2.解析文件 3.线程池批量新增

  //1.验证上传文件是否非空

  if(!file.isEmpty()){

  //2.获取上传内容

  InputStream is=file.getInputStream();

  //3.解析Excel

  EasyExcel.read(is,Department.class,new PageReadListener

  ((list)->{

  //使用线程池,保证每个线程处理的数据量不超过1000条

  //每个线程处理1000条数据,然后根据数据进行分片,每次计算每个任务完成的数据量的范围

  int i=0;

  int j=list.size()%1000==0?list.size()/1000:list.size()/1000+1;

  //循环添加任务到线程池中

  for(int m=1;m<=j;m++){

  ArrayList l=new ArrayList();

  l.addAll(list.subList((m-1)*1000,m*1000));

  ThreadPoolUtil.getInstance().poolExecutor.execute(()->{

  //4.调用 dao 实现批量新增

  dao.addBatch(l);

  });

  }

  })).sheet().doRead();

  }

  return R.ok();

  }

  有没有发现,老师自己封装了一个线程池的工具类?对!这里就是老师自己封装的工具模板,具体代码如下:

  //采用单例模式的IoDH封装线程池的工具类

  public class ThreadPoolUtil {

  //线程池对象

  public ThreadPoolExecutor poolExecutor;

  //构造函数私有化

  private ThreadPoolUtil(){

  //完成线程池对象的实例化

  poolExecutor=new ThreadPoolExecutor(4,10,3, TimeUnit.SECONDS,

  new ArrayBlockingQueue<>(20),

  Executors.defaultThreadFactory(),

  new ThreadPoolExecutor.AbortPolicy());

  }

  //静态内部类 完成对象的实例化

  private static class PoolInner{

  private final static ThreadPoolUtil pool=new ThreadPoolUtil();

  }

  //获取唯一实例

  public static ThreadPoolUtil getInstance(){

  return PoolInner.pool;

  }

  }

  代码中不仅使用了线程池,而且用到了设计模式,这里用的是单例设计模式,而且还是基于IoDH实现的。这样一来,不仅这个需求解决了,而且代码的逼格还有点高哦。

  四. 小结

  好了,老师想表达的就这么多,但最后还是要再给大家啰嗦几句。

  线程池适合处理耗时的任务,可以充分使用目前服务器的硬件资源,加快处理的速度;

  使用线程池时,不要死板,要结合自己的实际业务需求;

  先写出基本的代码,然后再进行测试,一定要测试,至于说线程池的核心参数该如何设置,还是得根据你们实际的请求来决定。

声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。

猜你喜欢LIKE

清除浮动是怎么回事?

2023-02-21

客户端向服务器发送请求的过程

2023-02-21

什么是宽高自适应呢?

2023-02-21

最新文章NEW

Java项目中到底该怎么使用线程池?

2023-02-21

Oozie和Azkaban的区别

2023-02-21

如何进行权限控制?

2023-02-21

相关推荐HOT

更多>>

快速通道 更多>>

最新开班信息 更多>>

网友热搜 更多>>