Java线程池ThreadPoolExector

分析过很多遍,面试的常考点,每次面试又得重新看,自己写到面试整理里了,这次发出来
ThreadPoolExecutor

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

用给定的初始参数创建新的 ThreadPoolExecutor。
参数:
corePoolSize - 池中所保存的线程数,包括空闲线程。
maximumPoolSize - 池中允许的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
threadFactory - 执行程序创建新线程时使用的工厂。
handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
抛出:
IllegalArgumentException - 如果 corePoolSize 或 keepAliveTime 小于 0,或者 maximumPoolSize 小于等于 0,或者 corePoolSize 大于 maximumPoolSize。
NullPointerException - 如果 workQueue、threadFactory 或 handler 为 null。

在创建线程池的时候,第一次使用的时候线程池中并没有线程,当有任务到达的时候才会开始创建线程来执行任务,直到池中的线程数到达corePoolSize之后,会将之后的任务添加到任务队列中进行缓存,这是为了防止任务过多不能及时响应。然后尝试创建新的线程来执行任务。
例如:new ThreadPoolExecutor(5,20,30L,TimeUnit.SECONDS,new LinkedBlockingQueue(10));
指定的核心线程数为5,线程池中最多可以容纳的线程为20个,当超过核心线程数之外的线程陷入空闲状态超过30秒(30秒还没等到任务)时这些线程就会被终止,但是核心线程之内的线程不论空闲多久都是不会被回收的,会一直保存在线程池中,下次在执行的任务的时候就可以直接拿来用。注意这里指定了阻塞队列的大小为10,队列中最多缓存10个任务,队列满了之后就会创建新的线程来执行任务,直到到达最大的线程数,如果任务还是执行不完就会抛出拒绝执行的异常。如果是在web请求中,任务较多可以不指定阻塞队列的大小这样就是无界队列,默认大小为Integer.MAX_VALUE,只要阻塞队列不满就不会去创建新的线程去执行任务,线程池中最多只有核心线程数个线程,设定的最大线程数就不会起作用。
假如现在来了21个任务,就会先创建5个线程来执行任务,然后先将10个任务添加到阻塞队列中,等到阻塞队列满了之后,然后开始创建10个新的线程来执队列中的10个任务,然后将剩下的5个任务再放到阻塞队列中,等其他任务执行完毕之后,再执行。对于非核心线程执行完任务知乎它的生命就结束了,但是还有5个核心线程会一直保存在线程池中,当下次再有任务到达的时候,可以直接从线程中取出来用。

package test;


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolTest {
    public static void main(String[] args){
        BlockingQueue<Runnable> workQueue=new ArrayBlockingQueue<Runnable>(3);
        ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,15, 30L,TimeUnit.SECONDS,workQueue);
        for (int i=1;i<=20;i++){
            tpe.execute(new MyTask("Thread-"+i));
        }
/*
假如现在共有20个任务
先创建5个核心线程执行任务 (在执行的任务:1,2,3,4,5,线程数:5)
然后从剩下的15个任务中
拿3个任务(6,7,8)放到工作队列中,队满
开始创建3个线程执行队列中的任务   (在执行的任务:1,2,3,4,5,6,7,8,线程数:8)
再拿3个任务(9,10,11)放到队列中,队满
再创建3个线程执行队列中的任务     (在执行的任务:1,2,3,4,5,6,7,8,9,10,11,线程数:11)
再拿3个任务(12,13,14)放到队列中,队满
再创建3个线程执行队列中的任务    (在执行的任务:1,2,3,4,5,6,7,8,9,10,11,12,13,14,线程数:14)
再拿3个任务(15,16,17)放到队列中,队满
再创建1个线程执行队列中的任务    (在执行的任务:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 线程数:15)
再放一个任务(18)到队列中,队满  (队列中:16,17,18)
线程数15个已达最大值,拒绝执行(19,20)
 */

    }
}

class MyTask implements Runnable{
    private String name;

    public MyTask(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name+" is running........");
    }
}

运行结果:


Thread-1 is running........
Thread-6 is running........
Thread-7 is running........
Thread-8 is running........
Thread-2 is running........
Thread-3 is running........
Thread-9 is running........
Thread-4 is running........
Thread-10 is running........
Thread-5 is running........
Thread-15 is running........
Thread-11 is running........
Thread-12 is running........
Thread-13 is running........
Thread-16 is running........
Thread-14 is running........
Thread-17 is running........
Thread-18 is running........
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task test.MyTask@355da254 rejected from java.util.concurrent.ThreadPoolExecutor@4dc63996[Running, pool size = 15, active threads = 0, queued tasks = 0, completed tasks = 18]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at test.ThreadPoolTest.main(ThreadPoolTest.java:16)

posted @ 2019-07-12 20:51  快乐的内啡肽呀  阅读(54)  评论(0)    收藏  举报