自己对线程池的理解

     工作中难免会遇到需要使用线程的地方,在使用线程的过程中,线程池我觉得是非常有必要去简单了解一下的;这里我会将自己所体会的感悟的一些基本内容分享出来,希望能对少数人有所帮助;如果有不对的地方,还请各位帮忙指出。

为什么使用线程池?

     在Java中,如果每当一个请求到达就创建一个新线程,开销是相当大的。在实际使用中,每个请求创建新线程的服务器在创建和销毁线程上花费的时间和消耗的系统资源,甚至可能要比花在实际处理实际的用户请求的时间和资源要多的多。
     线程池主要用来解决线程生命周期开销问题和资源不足问题,通过对多个任务重用线程,线程创建的开销被分摊到多个任务上了,而且由于在请求到达时线程已经存在,所以消除了创建所带来的延迟。这样,就可以立即请求服务,使应用程序响应更快。另外,通过适当的调整线程池中的线程数据可以防止出现资源不足的情况。

ThreadPoolExecutor类

  1. 根据corePoolSizemaxiMumPoolSize设置的边界自动调整池大小
  2. 当新任务在execute(Runnable)中提交时,如果运行的线程小于corePoolSize,则创建新的线程来处理请求,即使其他辅助线程时空闲的。
  3. 当运行的线程大于corePoolSize而小于maximumPoolSize,则仅当队列满时才创建新线程。
  4. 如果设置的corePoolSizemaximumPoolSize相同,则创建了固定大小的线程池。
1.它所生成的一些常用的线程池:

      ThreadPoolExecutor是Executors类的实现,Executors类里面提供了一些静态工厂,生成一些常用的线程池:
      newSingleThreadPool:
     创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
在这里插入图片描述
      newFixedThreadPool:
     创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
在这里插入图片描述
      newCachedThreadPool:
      创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
在这里插入图片描述
     在实际项目中,我一般使用的是固定的线程池;

2.四种处理策略:
  1. CallerRunsPolicy:
    线程调用运行该任务的execute本身,池中没有资源,则调用execute本身,能够减缓新任务的提交速度;
    在这里插入图片描述
  2. AbortPolicy:
    处理程序遭到拒绝就抛出异常,直接丢弃任务;
    在这里插入图片描述
  3. DiscardPolicy:
    与AbortPolicy几乎一样,只不过这种策略不会抛出异常,直接丢弃任务;
    在这里插入图片描述
  4. DiscarOldestPolicy:
    如果执行程序尚未关闭,则处于工作队列头部的任务将被删除,然后重新执行程序(如果再失败,就继续重复此过程)
    在这里插入图片描述
3.BlockingQueue:

在这里插入图片描述

4.有界队列与无界队列:
  • 有界队列:
    不指定任务队列的个数
    new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue());
    如果请求任务源源不断的过来,而任务处理的时间变长,那么在任务队列中就会堵塞大量的请求,而一般来说这些请求都是有超时时间设置的;假设请求是通过套接字过来,当我们的后端处理进程处理完一个请求后,从队列中拿下一个任务。
  • 无界队列:
    指定任务队列的个数
    new ThreadPoolExecutor(2, 4,60,TimeUnit.SECONDS, queue,new DaemonThreadFactory(poolName), new ThreadPoolExecutor.AbortPolicy());
    corePoolSize 为2;
    maximumPoolSize 为4;
    任务队列大小 为2;
    这里会根据有界队列时候线程池的执行顺序,当新任务在方法execute中提交时,如果运行的线程小于corePoolSize,则创建新线程来处理请求。如果大于corePoolSize而小于maximumPoolSieze,则仅当队列满时才创建新线程。如果已经达到了maximumPoolSize,并且队列已经满了,就会拒绝继续进来的请求;
    所以,这里不难看出;虽然这里可能会使部分的请求任务失败,但不至于会让整个系统处于崩溃的地步。通过有界队列,可以实现系统的过载保护,在高压的情况下,我们系统的处理能力不会变为0,还能正常的对外服务。
5.keepAliveTime:
 ThreadPoolExecutor中的额定线程数是由corePoolSize决定的,当任务数量超过额定线程数,则将任务缓存在BlockingQueue之中,当发现如果连queue也放不下了,就会再创建几个线程,当创建线程后数量大于maximumPoolSize,接下来就会发生两种状况:
  • 任务不过来------keepAliveTime
    当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。

  • 任务任然过来------RejectedxecutionHandler
    根据设定的拒绝策略来执行。

实际运用
  • 生成一个我们需要的线程池:(一般为固定线程池,有界队列,线程数看并发量)
    在这里插入图片描述

  • 把任务放在线程中去执行:(一般建议使用java8的Lambda表达式)
    在这里插入图片描述

  • 使用Future包装线程任务的执行结果:
    在这里插入图片描述

  • 遍历结果集,拿到我们线程执行任务的结果:
    在这里插入图片描述
    (附上一个在Http调用外部接口常用的JSON转对象的方法)
    List idList = JSON.parseObject((String) ids, new TypeReference<List>() {});

    将JSON字符串转换成任何自己想要的类型;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值