线程池ThreadPoolExecutor

一 概述

1.线程池产生背景

在多线程环境下,频繁地创建与销毁线程会耗费大量的系统资源,降低运行性能,因此产生了一种设计思想:将创建好的线程放到一个容器中,需要时从容器取得线程,使用完毕将线程归还容器,这样就可以重复利用线程,避免了重复创建与销毁造成的资源消耗,提高了性能。

2.什么是线程池?

元素:线程。
本质:容器。
设计目的:使得线程能够被重复使用,降低系统消耗。
一个以多个线程为元素、通过重复使用降低系统消耗的容器。

二 ThreadPoolExecutor

该类是线程池思想的核心类。
一个代表性的构造方法;

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

1.coolPoolSize

核心池大小。这个数字是根据一般情况下并发访问的线程数目设定的。默认情况下,线程池创建完毕后,池中并没有线程,有任务到达以后才开始创建线程。

2.maximumPoolSize

线程池中允许出现的最大线程数。维护线程需要消耗系统资源,最大线程数目的设定既考虑高峰时期最大并发访问数量,也兼顾了系统性能。

3.keepAliveTime

这个参数针对的是超出核心池大小的多余线程。设定一个时间,如果多余线程空闲时间超过该值,线程会被终止。默认情况下,只有当线程数目大于核心池大小时才有效,如果allowCoreThreadTimeOut设定为true,当线程数目小于核心池大小时也有效。

4.unit

keepAliveTime的单位。

5.workQueue

一个阻塞队列,用来存储等待执行的任务。BlockingQueue有几个常用的实现类:

  • ArrayBlockingQueue:不常用。
  • LinkedBlockingQueue:常用。
  • SynchronousQueue:常用。

6.threadFactory

线程工厂,用来创建线程。

7.handler

当线程数目到达最大值时,拒绝处理任务时采取的策略。

三 执行过程

1.当线程数目小于核心数目时,每来一个任务就创建一个线程去执行该任务。
2.当线程数目大于等于核心数目时,首先尝试将新到达的任务添加到任务缓存队列中,若添加成功,等待空闲线程执行该任务,添加失败尝试创建新的线程处理该任务。
3.如果线程达到最大数目,新任务达到时会采取拒绝处理策略。

execute()是ThreadPoolExecutor的核心方法,下面对该源码进行分析:

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn‘t, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
       //workerCountOf(c)用于获取线程池中当前线程数目
        if (workerCountOf(c) < corePoolSize) {
            //addWorker(command,true)创建新的线程执行该任务
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //当线程数目大于等于corePoolSize时,首先尝试将任务添加到任务缓存队列中
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //如果任务缓存队列已满,尝试创建新的线程
        else if (!addWorker(command, false))
            reject(command);
    }

addWorker(Runnable firstTask, boolean core)源码:

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
           ........................................................................

            for (;;) {
                int wc = workerCountOf(c);
               //当core=true时,如果线程数目小于corePoolSize,程序继续执行,创建新线程;当core=false时,如果线程数目大于等于maximumPoolSize,程序终止执行,返回                 false,不会创建新的线程
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            //为任务创建一个新的线程
            w = new Worker(firstTask);
            ..............................................
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

四 使用

通常不直接使用ThreadPoolExecutor的构造方法来创建对象,而是使用Executors的静态方法来创建对象。

newCachedThreadPool();

corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,使用SynchronousQueue作为任务缓存队列,如果线程池中没有可用的线程,每来一个任务创建一个线程。

newFixedThreadPool(int nThreads);

corePoolSize=nThreads,maximumPoolSize=nThreads,keepAliveTime=0s,使用LinkedBlockingQueue作为任务缓存队列。
线程池执行对象创创建完毕以后,将任务通过execute(Runnable command)方法提交给线程池执行对象即可。

参考:

http://www.cnblogs.com/dolphin0520/p/3932921.html

时间: 2024-11-03 20:48:15

线程池ThreadPoolExecutor的相关文章

java线程API学习 线程池ThreadPoolExecutor(转)

线程池ThreadPoolExecutor继承自ExecutorService.是jdk1.5加入的新特性,将提交执行的任务在内部线程池中的可用线程中执行. 构造函数 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, Rejected

《Java源码分析》:线程池 ThreadPoolExecutor

<Java源码分析>:线程池 ThreadPoolExecutor ThreadPoolExecutor是ExecutorService的一张实现,但是是间接实现. ThreadPoolExecutor是继承AbstractExecutorService.而AbstractExecutorService实现了ExecutorService接口. 在介绍细节的之前,先介绍下ThreadPoolExecutor的结构 1.线程池需要支持多个线程并发执行,因此有一个线程集合Collection来执行

线程池ThreadPoolExecutor使用简介(转)

一.简介 线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) corePoolSize: 线程池维护线程的最少数量 maximumPool

[转载]线程池ThreadPoolExecutor使用简介

一.简介 线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) corePoolSize: 线程池维护线程的最少数量

线程池(ThreadPoolExecutor JDK1.7)

平常我们经常都会使用到线程池,但是有没考虑过为什么需要使用线程池呢?下面我列举一下问题,大家可以思考一下 1.当前服务器的硬件环境是多少核的CPU,它和线程的关系又是什么? 2.jvm能创建多少个线程? 3.多线程主要解决什么问题? 4.你使用线程池的目的是什么? 以上几个问题都是帮助你更好的使用java的线程(还可以衍生更多的小问题,如:jvm维护线程的消耗,cpu调度线程的消耗,应该使用多少个线程才能最大化利用多核CPU..).答案需要自己去百度,我这也讲不好,反而误导大家. 线程池顾名思义

Java线程池ThreadPoolExecutor使用和分析(三) - 终止线程池原理

相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池ThreadPoolExecutor使用和分析(三) - 终止线程池原理 以下是本文的目录大纲: 一.shutdown()  --  温柔的终止线程池 interruptIdleWorkers()  --  中断空闲worker tryTerminate()  --  尝试终止线程池 二.shutdown

java 线程池 ---- ThreadPoolExecutor 类

执行流程 1, 创建线程池后, 默认不会创建线程, 等到有任务带来才创建线程, 即一个线程处理一个任务 2, 当线程数量达到核心线程数时, 任务放进队列, 如果放入队列失败, 创建新线程处理任务(此时线程池线程数大于核心线程数) 3, 如果线程数大于最大线程数, 执行拒绝策略处理任务 构造方法 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, Block

java面试总躲不过的并发(一): 线程池ThreadPoolExecutor基础梳理

本文核心:线程池ThreadPoolExecutor基础梳理 一.实现多线程的方式 1.继承Thread类,重写其run方法 2.实现Runnable接口,实现run方法 3.实现Callable接口,实现call方法 由于Java的设计,只支持单继承,但是支持多实现形式,所以一般面向接口开发,Runnable接口与Callable接口的区别在于Callable接口中的call方法是带返回值的,其返回一个Future的异步类,我们可以通过Future的get方法获取结果,如果线程还没有执行完,g

如何获取线程池ThreadPoolExecutor正在运行的线程

如何获取线程池ThreadPoolExecutor正在运行的线程?这里有两种方法,如下代码: package com.itbac.thread; import java.util.HashSet; import java.util.Set; import java.util.concurrent.*; import java.util.stream.Stream; /** * ThreadPoolExecutor 的 beforeExecute() 和 afterExecute()方法, * 不

并发编程之线程池ThreadPoolExecutor

前言 在我们平时自己写线程的测试demo时,一般都是用new Thread的方式来创建线程.但是,我们知道创建线程对象,就会在内存中开辟空间,而线程中的任务执行完毕之后,就会销毁. 单个线程的话还好,如果线程的并发数量上来之后,就会频繁的创建和销毁对象.这样,势必会消耗大量的系统资源,进而影响执行效率. 所以,线程池就应运而生. 线程池ThreadPoolExecutor 可以通过idea先看下线程池的类图,了解一下它的继承关系和大概结构. 它继承自AbstractExecutorService