池技术

作者: 哓晓的故事 | 来源:发表于2018-12-24 14:30 被阅读0次

线程池

ThreadPoolExecutor.png

优点

重用线程,减少创建和销毁线程的开销(时间,资源)
防止线程相互竞争资源

线程池类型

  1. newFixedThreadPool,coreSize和maxSize大小一致,keepAlived=0永不超时,队列为LinkedBlockingQueue无限制阻塞队列
  2. newCachedThreadPool,maxSize=Integer.MAX_VALUE,keepAlived=60,队列为SynchronousQueue
  3. newSingleThreadPool,coreSize=maxSize=1,keepAlived=0永不超时,队列为LinkedBlockingQueue无限制阻塞队列
  4. newScheduledThreadPool

自定义线程池

通过继承ThreadPoolExecutor来实现自定义线程池
其中核心在于定义几个关键的构造函数参数

public ThreadPoolExecutor(int corePoolSize, // 一直存活的线程数
                              int maximumPoolSize,  // 最多可以同时运行的线程数
                              long keepAliveTime, // 大于core的线程空闲后,maxCoreSize存活数量的时间
                              TimeUnit unit, // 时间单位
                              BlockingQueue<Runnable> workQueue, // 存储等待的线程数量队列(大于coreSize的都存储至此)
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) // 线程池拒绝时的动作
  1. 如果当前线程池线程数目小于 corePoolSize(核心池还没满呢),那么就创建一个新线程去处理任务。
  2. 如果corePoolSize已经了,来了一个新的任务后,会尝试将其添加任务队列中,如果成功,则等待空闲线程将其从队列中取出并且执行,如果队列已经满了,则继续下一步。
    3.此时,如果线程池线程数量小于 maximumPoolSize,则创建一个新线程执行该任务(不是从阻塞队列中出一个任务执行,因此不是FIFO),否则,那就说明线程池到了最大饱和能力了,没办法再处理了,此时就按照拒绝策略来处理。(就是构造函数当中的Handler对象)。
  3. 如果线程池的线程数量大于corePoolSize,则当某个线程的空闲时间超过了keepAliveTime,那么这个线程就要被kill了,直到线程池中线程数量不大于corePoolSize为止。
阻塞队列的选择

LinkedBlockingQueue: 无限阻塞队列
ArrayBlockingQueue: 有限阻塞队列
PriorityBlockingQueue: 有限带权阻塞队列
SynchronousQueue

饱和策略

Abort(中止):抛出RejectedExecutionException异常
Discard(丢弃):放弃任务
DiscardOldest(丢弃最旧):放弃最老的任务,然后重新提交任务
CallerRuns(调用者运行):将任务推回调用者,来减缓新任务流

平缓劣化

当线程池满,主线程不调用accept,会阻塞在TCP层,转嫁到用户头上

配置

ThreadPoolExecutor允许通过setter修改配置项,可以使用unconfigurableExecutorService来设置一个代理屏蔽对线程池参数的修改

切面

定制化的线程池可以使用
beforeExecute(执行前),afterExecute(执行后),terminated(线程池关闭后)来实现切面

阻塞和非阻塞请求

executor.execute(); 这个是非阻塞提交,返回future标识状态
executor.invokeAll(); 这个是阻塞批量提交,全部执行完成,返回批量future标识状态
executor.invokeAny(); 这个是阻塞批量提交,只要有一个执行完成,返回批量future标识状态

submit() -> FutureTask 和 Future

FutureTask是一个阻塞闭锁,实现了Future
get()没有获得值时会阻塞
submit方法实际上是newForFuture();

ThreadFactory

线程池内部线程重新定义过的线程对象,因此针对外部线程interrupt,在线程池内部的线程是无法感应
如果想对内部做干扰,需要自定应ThreadFactory,此工厂可以定义每个生成的threadName,是否精灵线程,线程级别

此对象内部会包装UncaughtExceptionHandle来捕获不可知异常,但是只在execute()生效,submit()会由Future封装

关闭和等待

shutdown() 平滑关闭, 会执行阻塞队列任务
shutdownNow()强制关闭,使用interrupt,不会执行阻塞队列中的任务,并且返回未执行任务列表
关闭后提交到ExecutorService中的任务,会被拒绝执行处器理处理,抛出RejectedExecutionException,而这个异常并不是关闭时才抛出的,简单地放弃任务也会抛出此异常
awaitTermination()阻塞当前线程,设置超时时间,等待任务完成
区别:
shutdown后还可以提交任务,awaitTermination不可以提交任务

自定义线程池

自定义线程池时,如果任务是 CPU 密集型(需要进行大量计算、处理),则应该配置尽量少的线程,比如 CPU 个数 + 1,这样可以避免出现每个线程都需要使用很长时间但是有太多线程争抢资源的情况;
如果任务是IO密集型(主要时间都在 I/O,CPU 空闲时间比较多),则应该配置多一些线程,比如 CPU 数的两倍,这样可以更高地压榨 CPU

为了错误避免创建过多线程导致系统奔溃,建议使用有界队列。因为它在无法添加更多任务时会拒绝任务,这样可以提前预警,避免影响整个系统

ThreadPoolExecutor源码分析

连接池


对象池

相关文章

  • 池技术使用-commons-pool2

    池技术 日常搬砖过程中对池技术的接触很多,最具代表的是连接池。连接池也是一种池技术,本质上都是对象池。common...

  • 池技术

    线程池 优点 重用线程,减少创建和销毁线程的开销(时间,资源)防止线程相互竞争资源 线程池类型 newFixedT...

  • 31.内存池、进程池、线程池

    首先介绍一个概念池化技术 。池化技术就是:提前保存大量的资源,以备不时之需以及重复使用。池化技术应用广泛,如内存池...

  • commons-pool2 池化技术探究

    一、前言 我们经常会接触各种池化的技术或者概念,包括对象池、连接池、线程池等,池化技术最大的好处就是实现对象的重复...

  • DBUtiles的使用

    自定义连接池: 学会用resourcebundle来加载properties文件 运用连接池的技术 连接池技术原理...

  • 算法竞赛常用技术

    内存池技术

  • 线程池

    1.为什么要使用线程池?2.线程池的基本原理是什么?3.怎么学习线程池?线程池使用了池化技术。池化技术用于我们常见...

  • Java线程池深度研究

    一、概述 池化技术相比大家已经屡见不鲜了,线程池、数据库连接池、Http 连接池等等都是对这个思想的应用。池化技术...

  • 数据库连接池、线程池等管理的关键点,你知道吗?

    在Java应用开发中经常会用到连接池、线程池等池化技术。池化(pool)技术的本质是通过复用对象、连接等资源,减少...

  • Mybatis知识day03 连接池&动态SQL&多表查询

    一、Mybatis 连接池 1.1Mybatis 的连接池技术采用的是自己的连接池技术。在 Mybatis的 Sq...

网友评论

      本文标题:池技术

      本文链接:https://www.haomeiwen.com/subject/vlhzkqtx.html