多线程3——线程池的创建与使用

简介

查看这篇文章,最好先看一下我转载的Executor框架详解和Java线程池之ThreadPoolExecutor(文章内容有点长,最好仔细的看,且打开代码工具对照源码)。这篇文章也参考了这两篇博客。

为什么要使用线程池

1. 降低资源的消耗
通过重复利用已创建的线程,降低线程创建和销毁所造成的消耗
2. 提高响应速度
当任务到达时,任务可以不需要等到线程创建就能立即执行
3. 提高线程的可管理性
线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。

创建线程池的主要两种放式

1.使用ExecutorService(是接口,继承了Executor接口),用Executors里的静态方法创建,
Executors代码中也有使用ThreadPoolExecutor创建线程池(只是多设置了默认值);
2.使用ThreadPoolExecutor 。继承AbstractExecutorService, AbstractExecutorService实现ExecutorService
注意:
《阿里巴巴开发手册》禁止使用Executors创建线程池,而是使用ThreadPoolExecutor创建线程池。
为什么:

Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE(Integer的最大值2147483647),可能会堆积大量的请求,从而导致 OOM。
(什么是OOM? OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError。)
2)CachedThreadPool 和 ScheduledThreadPool(ScheduledThreadPoolExecutor):
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

源码解析

ExecutorService源码解析

//Executor 源码
public interface Executor {
    void execute(Runnable command);
}

所有已知实现类:
AbstractExecutorService , ForkJoinPool , ScheduledThreadPoolExecutor , ThreadPoolExecutor

package java.util.concurrent;
import java.util.List;
import java.util.Collection;
public interface ExecutorService extends Executor {
	//启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。 
	void shutdown();
	//尝试停止所有主动执行的任务,停止等待任务的处理,并返回正在等待执行的任务列表。
	List<Runnable> shutdownNow();
	//如果此执行者已关闭,则返回 true 。 
	boolean isShutdown();
	//如果所有任务在关闭后完成,则返回 true 。 
	boolean isTerminated();
	//阻止所有任务在关闭请求完成后执行,或发生超时,或当前线程中断,以先到者为准。 
    boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
     //提交值返回任务以执行,并返回代表任务待处理结果的Future。 
    <T> Future<T> submit(Callable<T> task);
    //提交一个可运行的任务执行,并返回一个表示该任务的未来。 
	<T> Future<T> submit(Runnable task, T result);
	//提交一个可运行的任务执行,并返回一个表示该任务的未来。
	 Future<?> submit(Runnable task);
	 //执行给定的任务,返回持有他们的状态和结果的所有完成的期货列表。 
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;
	//执行给定的任务,返回在所有完成或超时到期时持有其状态和结果的期货列表,以先发生者为准。
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;
	//执行给定的任务,返回一个成功完成的结果(即没有抛出异常),如果有的话。 
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;
     //执行给定的任务,返回一个已经成功完成的结果(即,不抛出异常),如果有的话在给定的超时之前过去。    
	<T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

Executors常用方法源码解析

//从new LinkedBlockingQueue()没有传参可以看出队列长度是无界的(即Integer的最大值)
//FixedThreadPool,创建固定数量的线程池
 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
  public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }  
    //SingleThreadExecutor是使用单个worker线程的Executor。特点是使用单个工作线程执行任务。
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

//从 Integer.MAX_VALUE可以看出创建线程是无界的。即创建线程数量为Integer.MAX_VALUE
//CachedThreadPool是一个”无限“容量的线程池,它会根据需要创建新线程。特点是可以根据需要来创建新的线程执行任务,
//没有特定的corePool。下面是它的构造方法:
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    } 
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }   

ScheduledThreadPoolExecutor类

//允许创建线程数量为Integer.MAX_VALUE
public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

ThreadPoolExecutor源码解析

主要是利用ThreadPoolExecutor 的4个构造方法创建线程

//jdk1.8
//ThreadPoolExecutor类的源码(创建线程池)
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,       
                          BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
//多了ThreadFactory threadFactory(自定义线程创建)
 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                           BlockingQueue<Runnable> workQueue,
                           ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }  
                             
                            
                             
    //RejectedExecutionHandler handler(饱和策略)
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,  long keepAliveTime, TimeUnit unit,
                               BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
    //ThreadFactory threadFactory,RejectedExecutionHandler handler
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,  long keepAliveTime, TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

ThreadPoolExecutor构造方法中的参数解释:
必须的参数:
corePoolSize:线程池的基本大小;
maximumPoolSize:最大线程数;
keepAliveTime:线程池的工作线程空闲后,保持存活的时间;
TimeUnit:线程活动保持时间的单位;

TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒

workQueue: 用于缓存任务的阻塞队列,它决定了缓存任务的排队策略。对于不同的应用场景我们可能会采取不同的排队策略,这就需要不同类型的阻塞队列,在线程池中常用的阻塞队列是 LinkedBlockingQueue和SynchronousQueue

// 是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
ArrayBlockingQueue;
//一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,
//吞吐量通常要高于 ArrayBlockingQueue。静态工厂方法 Executors.newFixedThreadPool() || newSingleThreadExecutor 使用了这个队列。
LinkedBlockingQueue;
//一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,
//静态工厂方法 Executors.newCachedThreadPool 使用了这个队列。
SynchronousQueue;
//一个具有优先级得无限阻塞队列。
PriorityBlockingQueue

可选的:
ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字,Debug和定位问题时非常又帮助。
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 

在ThreadPoolExecutor类中有几个非常重要的方法:

execute()
submit()
shutdown()
shutdownNow()

execute() 方法实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,交由线程池去执行。
submit() 方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果,去看submit()方法的实现,会发现它实际上还是调用的execute()方法,只不过它利用了Future来获取任务执行结果。
shutdown()shutdownNow() 是用来关闭线程池的。

线程池状态

	private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3      	  //32-3=29,即线程数量所占位数
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1; //低29位表示最大线程数,即2的29次方减1

    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;	        //int型变量高3位(含符号位)101表RUNING
    private static final int SHUTDOWN   =  0 << COUNT_BITS;         //高3位000
    private static final int STOP       =  1 << COUNT_BITS;		      //高3位001
    private static final int TIDYING    =  2 << COUNT_BITS;	      //高3位010
    private static final int TERMINATED =  3 << COUNT_BITS;      //高3位011

    
    // Packing and unpacking ctl
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
    private static int workerCountOf(int c)  { return c & CAPACITY; }
    private static int ctlOf(int rs, int wc) { return rs | wc; }

补充:
ctl这个变量使用来干嘛的呢?它的作用有点类似我们在《ReadWriteLock接口及其实现ReentrantReadWriteLock》中提到的读写锁有读、写两个同步状态,而AQS则只提供了state一个int型变量,此时将state高16位表示为读状态,低16位表示为写状态。这里的clt同样也是,它表示了两个概念:

线程池主要控制的状态是ctl,它是一个原子的整数,其包含两个概念字段:

  • workerCount:有效的线程数量
  • runState:线程池的状态

int型变量一共有32位,线程池的五种状态runState至少需要3位来表示,故workCount只能有29位,所以代码中规定线程池的有效线程数最多为2的29方-1。

为了在一个整型值里面包含这两个字段,我们限制workerCount最多2的29次方减1
runState的值有这样几种:

RUNNING: 接受新的任务,并处理队列中的任务
SHUTDOWN: 不接受新的任务,继续处理队列中的任务
STOP: 不接受新的任务,也不处理队列中的任务,并且中断正在处理的任务
TIDYING: 所有任务都结束了,workerCount是0,通过调用terminated()方法转换状态
TERMINATED: terminated()方法已经完成

状态之间的转换时这样的:
RUNNING -> SHUTDOWN
调用shutdown()方法,或者隐式的调用finalize()方法

(RUNNING or SHUTDOWN) -> STOP
调用shoutdownNow()方法

SHUTDOWN -> TIDYING
当队列和池都是空的时候

STOP -> TIDYING
当池是空的时候

TIDYING -> TERMINATED
当terminated()方法调用完成时

Integer.SIZE=32
Integer.SIZE - 3 = 29
所以,COUNT_BITS = 29
最高3位存储runState

ThreadPoolExecutor类中其他的一些比较重要成员变量:

private final BlockingQueue<Runnable> workQueue;              //任务缓存队列,用来存放等待执行的任务
private final ReentrantLock mainLock = new ReentrantLock();   //线程池的主要状态锁,对线程池状态(比如线程池大小
                                                              //、runState等)的改变都要使用这个锁
private final HashSet<Worker> workers = new HashSet<Worker>();  //用来存放工作集
 
private volatile long  keepAliveTime;    //线程存货时间   
private volatile boolean allowCoreThreadTimeOut;   //是否允许为核心线程设置存活时间
private volatile int   corePoolSize;     //核心池的大小(即线程池中的线程数目大于这个参数时,提交的任务会被放进任务缓存队列)
private volatile int   maximumPoolSize;   //线程池最大能容忍的线程数
 private volatile RejectedExecutionHandler handler; //任务拒绝策略
 private volatile ThreadFactory threadFactory;   //线程工厂,用来创建线程
 
private int largestPoolSize;   //用来记录线程池中曾经出现过的最大线程数
private long completedTaskCount;   //用来记录已经执行完毕的任务个数

ThreadPoolExecutor类中的execute()方法

//在将来某个时候执行给定的任务。 任务可以在新线程或现有的合并的线程中执行。 如果任务无法提交执行,
//由于此执行程序已关闭或已达到其容量,该任务将由当前的RejectedExecutionHandler处理。 
public void execute(Runnable command) {
		//判断提交的任务command是否为null,若是null,则抛出空指针异常;
        if (command == null)
            throw new NullPointerException();
       //由它可以获取到当前有效的线程数和线程池的状态(获取线程池的状态位)
        int c = ctl.get();
        //1.进入if中计算线程池的数量,如果小于线程池的核心线程数,就封装成一个工作(work),失败了继续获取线程池状态位;
        if (workerCountOf(c) < corePoolSize) {
        	//在addWorker中创建工作线程执行任务
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //2.判断线程池是否正常运行,正常的话就把当前线程添加到工作队列并且再次获取线程池状态位,
        if (isRunning(c) && workQueue.offer(command)) {//线程池是否处于运行状态,且是否任务插入任务队列成功
            int recheck = ctl.get();
            //如果没有运行的线程了,就把刚才添加的线程移除,移除成功后,使用拒绝策略
            if (! isRunning(recheck) && remove(command))//线程池是否处于运行状态,如果不是则使刚刚的任务出队
                reject(command);						//抛出RejectedExceptionException异常
             //如果线程池的线程数为0,那么就要添加一个空任务继续运行,以此来保证可以继续接收新任务而继续运行。   
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //3.如果核心线程满了,工作队列也饱和了,开启非核心线程也失败了就会拒绝,此时已经达到最大线程数了。
        else if (!addWorker(command, false))
            reject(command);  //抛出RejectedExceptionException异常
    }

从英文解释中,我们可以看到:基本分三步:

a) 开启线程执行任务,直到达到最大核心线程数

b) 达到核心线程数时,将接受的新任务放入工作队列

c) 当工作队列也放满后,就会开启线程(非核心)执行任务,直到到达最大线程数

d) 以上条件都不满足时,就执行默认的拒绝策略

ThreadPoolExecutor的addWork()源码:

private boolean addWorker(Runnable firstTask, boolean core) {
        retry: //循环标志
        for (;;) { 死循环
            int c = ctl.get();//获取状态位
            int rs = runStateOf(c);//计算线程池的状态

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;//这一段说的是线程池不能正常运行的情况:线程池状态关闭、任务为空、队列为空返回错误

            for (;;) {//死循环
                int wc = workerCountOf(c);//计算线程数
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;//如果线程数超出核心线程数,返回错误
                if (compareAndIncrementWorkerCount(c))//增加worker的数量
                    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是否添加成功
        Worker w = null;
        try {
            w = new Worker(firstTask);//封装成worker
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;//加锁
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());计算线程池状态

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;//worker添加成功
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();//启动刚刚添加的任务
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);//失败后执行的操作
        }
        return workerStarted;
}

从对源码的翻译中我们可以知道这个方法是有什么作用,简单说就是:创建任务,封装任务。

线程测试

public class ThreadPoolStudy {
    public static void main(String[] args) {
            //指定3个长度的工作队列
            LinkedBlockingDeque<Runnable> workQueue=new LinkedBlockingDeque<Runnable>(3);
            //指定线程池参数:核心线程数,线程池最大线程数量,活跃时间,工作队列
            ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor( 4, 7, 90,TimeUnit.SECONDS, workQueue);
            //指定线程池核心数为4,最大线程数量7,工作队列最大放入3个线程,模拟15个线程并发。
            for (int i = 0; i < 15; i++) {
                threadPoolExecutor.execute(new Thread(new TestThreadPool(), "线程:".concat(i+"")));
                System.out.println("线程池中活跃线程数"+threadPoolExecutor.getActiveCount());
                if(workQueue.size()>0){
                    System.out.println("被阻塞的线程数为:"+workQueue.size());
                  }
                }
        	 threadPoolExecutor.shutdown();

    }
    public static class TestThreadPool implements Runnable {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}

运行结果如下:

线程池中活跃线程数1
线程池中活跃线程数2
线程池中活跃线程数3
线程池中活跃线程数4
线程池中活跃线程数4
被阻塞的线程数为:1
线程池中活跃线程数4
被阻塞的线程数为:2
线程池中活跃线程数4
被阻塞的线程数为:3
线程池中活跃线程数5
被阻塞的线程数为:3
线程池中活跃线程数6
被阻塞的线程数为:3
线程池中活跃线程数7
被阻塞的线程数为:3
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task Thread[线程:10,5,main] rejected from java.util.concurrent.ThreadPoolExecutor@27d6c5e0[Running, pool size = 7, active threads = 7, queued tasks = 3, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at com.hai.interview.threadstudy.ThreadPoolStudy.main(ThreadPoolStudy.java:41)

RejectedExecutionException异常一般有两种原因造成:
第一种: 队列满了(即实际创建线程数大于maximumPoolSize+LinkedBlockingDeque(3),以上代码就是因为这个原因造成的。)
解决办法:

  1. 调整线程池饱和策略
//handler有四个选择:
//缺省策略
//抛出java.util.concurrent.RejectedExecutionException异常
new ThreadPoolExecutor.AbortPolicy();
//重试添加当前的任务,他会自动重复调用execute()方法
new ThreadPoolExecutor.CallerRunsPolicy();
//抛弃旧的任务
new ThreadPoolExecutor.DiscardOldestPolicy();
//抛弃当前的任务
ThreadPoolExecutor.DiscardPolicy();

2.扩大允许请求队列长度(此处需谨慎,可能会堆积大量请求,造成oom);

eg:FixedThreadPool 和 SingleThreadPool就是允许请求队列长度为Integer.MAX_VALUE.

3.扩大最大线程数(需谨慎,大量创建线程可能会导致oom)

eg:CachedThreadPool 和 ScheduledThreadPool就是允许创建线程数量为Integer.MAX_VALUE。

4.减小线程并发量。
第二种: 你的线程池ThreadPoolExecutor 显示的shutdown()之后,再向线程池提交任务的时候。如果你配置的拒绝策略是AbortPolicy的话,这个异常就会抛出来。
eg:

for (int i = 0; i < 15; i++) {
  threadPoolExecutor.execute(new Thread(new TestThreadPool(), "线程:".concat(i+"")));
  System.out.println("线程池中活跃线程数"+threadPoolExecutor.getActiveCount());
  if(workQueue.size()>0){
               System.out.println("被阻塞的线程数为:"+workQueue.size());
        }
      //线程池ThreadPoolExecutor 显示的shutdown()之后,再向线程池提交任务的时候。
	 threadPoolExecutor.shutdown();
   }

可以看到,创建了4个核心线程和3个非核心线程,当线程数超出了线程池可容纳的的最大数量,执行了拒绝策略Reject,说明队列和线程池都满了,线程池处于饱和状态,另外一个原因是完成的线程没有及时释放,而是进入了休眠。
线程池工作原理: 任务开始后,开始创建新的线程,当达到核心线程数后,新的任务进来不在创建新的线程,这时候把任务加入工作队列,当达到工作队列的长度后,新任务开始创建新的普通线程,直到数量达到线程池的最大核心数量,后面再有新任务则执行饱和策略或拒绝,抛出异常。

你可能感兴趣的:(线程)