线程池以及线程池的作用?线程池是如何创建线程的?平常项目中线程池的配置参数有哪些?各个参数又有什么含义?

1.线程池及线程池的作用:

线程池使应用能够更加充分合理地协调利用CPU、内存、网络、I/O等系统资源。

线程的创建需要开辟虚拟机栈、本地方法栈、程序计数器等线程私有的空间。

在线程销毁时需要回收这些系统资源。频繁地创建和销毁线程会浪费大量的系统资源,增加并发编程风险。

另外,在服务器负载过大的时候,如何让新的线程等待或者友好的拒绝服务?这些都是线程自身无法解决的。

所以需要通过线程池协调多个线程,并实现类似主次线程隔离、定时执行、周期执行等任务。

线程池的作用:

(1)利用线程池管理并复用线程、控制最大并发数等。

(2)实现任务线程队列缓存策略和拒绝机制。

(3)实现某些与时间相关的功能,如定时执行、周期执行等。

(4)隔离线程环境。比如,交易服务和搜索服务在同一台服务器上,分别开启两个线程池,交易线程的资源消耗明显要大;

因此,通过配置独立的线程池,将较慢的交易服务与较快的搜索服务隔离开,避免各自服务线程相互影响。

2.线程池是如何创建线程的:

首先从ThreadPoolExecutor构造方法学起,学习如何自定义ThreadFactory和RejectedExecutionHandler,并编写一个间的的线程池示例。然后通过

通过分析ThreadPoolExecutor的execute和addWorker两个核心方法,学习如何把任务线程加入到线程池中运行。ThreadPoolExecutor的构造方法如下:

 

    public ThreadPoolExecutor(
            int corePoolSize,        //第1个参数
            int maximumPoolSize, //第2个参数
            long keepAliveTime, //第3个参数
            TimeUnit unit, //第4个参数
            BlockingQueue<Runnable> workQueue, //第5个参数
            ThreadFactory threadFactory, //第6个参数
            RejectedExecutionHandler handler) { //第7个参数
        if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0) // 第一处
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)//第二处
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

 各个参数的含义:

  • 第1个参数 :corePoolSize 表示常驻核心线程数。如果等于0,则任务执行完成后,没有任何请求进入时销毁线程池的线程;如果大于0,即使本地任务执行完毕,核心线程也不会被销毁。这个值的设置非常关键,设置过大会浪费资源,设置的过小会导致线程频繁地创建或销毁。
  • 第2个参数:maximumPoolSize 表示线程池能够容纳同时执行的最大线程数。从上方的示例代码中第一处来看,必须大于或等于1。如果待执行的线程数大于此值,需要借助第5个参数的帮助。缓存在队列中。如果maximumPoolSize 与corePoolSize 相等,即是固定大小线程池。
  • 第3个参数:keepAliveTime 表示线程池中的线程空闲时间,当空闲时间达到KeepAliveTime 值时,线程被销毁,直到剩下corePoolSize 个线程为止,避免浪费内存和句柄资源。在默认情况下,当线程池的线程大于corePoolSize 时,keepAliveTime 才会起作用。但是ThreadPoolExecutor的allowCoreThreadTimeOut 变量设置为ture时,核心线程超时后也会被回收。
  • 第4个参数:TimeUnit 表示时间单位。keepAliveTime 的时间单位通常是TimeUnit.SECONDS。
  • 第5个参数:   workQueue 表示缓存队列。如果线程池里的线程数大于corePoolSize ,就会放到缓存队列,缓存队列满了会创建新线程到maximumPoolsize;直到当请求的线程数大于maximumPoolSize时,会执行设定的策略,默认是拒绝创建策略。(注意:当线程池里的线程数大于corePoolSize且小于maximumPoolSize时,这时候再有请求的线程就会放到缓存队列,注意只是放到缓存队列但是不创建新的线程,直到请求的线程存满缓存队列时,才会开始创建新的线程,直到maxmumPoolSize就会拒绝创建或者执行提前设定的策略。
  • 第6个参数:threadFactory 表示线程工厂。它用来生产一组相同任务的线程。线程池的命名是通过给这个factory增加组名前缀来实现的。在虚拟机栈分析时,就可以知道线程任务是由哪个线程工厂产生的。
  • 第7个参数:handler 表示执行拒绝策略的对象。当超过第5个参数workQueue的任务缓存区上限的时候,就可以通过该策略处理请求,这是一种简单的限流保护。友好的拒绝策略可以使如下三种:
  1. 保存到数据库进行削峰填谷。在空闲的时候再拿出来执行。
  2. 转向某个提示页面。
  3. 打印日志。
posted @ 2020-04-03 18:06  初仰  阅读(2069)  评论(0编辑  收藏  举报