【JUC】ThreadPoolExecutor的使用

ThreadPoolExecutor

使用此方法,更明确线程池的运行规则,规避资源耗尽的风险

可以认为是ExecutorService的实现类

线程池流程

  1. 线程先进入核心池运行;
  2. 核心池满了,进队列等待;
  3. 队列满了,就创建新线程,直到最大线程数满了,之外的线程就被拒绝rejected;

线程池参数

// 最多的七参构造器,前五个参数必须
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,	
                          ThreadFactory threadFactory,//线程工厂,可以不写
                          RejectedExecutionHandler handler)//拒绝策略,可以不写

ThreadPoolExecutor的四种构造器的各项参数:

  • corePoolSize:核心池的大小,并非线程的最大数量

    • maximumPoolSize > corePoolSize
    • 在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中
  • maximumPoolSize:线程池的最大线程数,表示线程池中最多能创建多少个线程

  • keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止

    • 默认:只有线程池内线程数大于corePoolSize的线程,keepAliveTime才会对其计时
    • 当一个线程的空闲时间大于keepAliveTime,则会被终止
    • 如果调用了allowCoreThreadTimeOut(boolean),线程池内线程数小于corePoolSize,keepAliveTime也会起作用
  • unit:参数keepAliveTime的时间单位(七种单位)

    TimeUnit.DAYS;              //天
    TimeUnit.HOURS;             //小时
    TimeUnit.MINUTES;           //分钟
    TimeUnit.SECONDS;           //秒
    TimeUnit.MILLISECONDS;      //毫秒
    TimeUnit.MICROSECONDS;      //微妙
    TimeUnit.NANOSECONDS;       //纳秒
    
  • workQueue:选择一个阻塞队列

    LinkedBlockingQueue;	// 常用,无界阻塞队列,不传值默认为Integer.MAX_VALUE,容易内存耗尽
    SynchronousQueue;
    ArrayBlockingQueue;
    PriorityBlockingQueue // 优先队列
    
  • threadFactory:线程工厂,主要用来创建线程。如果不传此参数,默认:Executors.defaultThreadFactory()

  • handler:表示当拒绝处理任务时的策略,有以下四种取值:

    如果不传此参数,默认:ThreadPoolExecutor.AbortPolicy

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

ThreadPoolExecutor的重要方法:

  • execute(Runnable command)

    通过这个方法可以向线程池提交一个任务,交由线程池去执行

    此方法在执行的时候,会判断当前线程数是否大于corePoolSize

    如果当前线程数大于corePoolSize,并且,当前线程池处于RUNNING状态,则将此任务加入任务缓冲队列

  • submit()

    内部调用execute()方法

    这个方法也是用来向线程池提交任务的,但是它和execute()方法不同

    它能够返回任务执行的结果,利用了Future来获取任务执行结果

  • shutdown()

    关闭线程池,此时线程池不能够接受新的任务,它会等待所有任务执行完毕

  • shutdownNow()

    关闭线程池,线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务

可视化线程池流程

这个例子演示了线程进入线程池的流程

线程会先占用核心池,满了之后去队列等待;

队列满了之后,如果还没有达到最大线程数量,继续创建线程;

到最大线程数,启动拒绝策略;

先看结果:

PoolSize: 1,Queue[]
PoolSize: 2,Queue[]
// 到这里,核心池满了,之后线程,进入队列
PoolSize: 2,Queue[Task_2]
PoolSize: 2,Queue[Task_2, Task_3]
PoolSize: 2,Queue[Task_2, Task_3, Task_4]
PoolSize: 2,Queue[Task_2, Task_3, Task_4, Task_5]
PoolSize: 2,Queue[Task_2, Task_3, Task_4, Task_5, Task_6]
// 队列满了,继续创建线程到线程池,这一个多余的线程会在等待,并倒计时keepAliveTime
PoolSize: 3,Queue[Task_2, Task_3, Task_4, Task_5, Task_6]
// 最大线程数已满,拒绝后续线程
Rejected:Task_8
PoolSize: 3,Queue[Task_2, Task_3, Task_4, Task_5, Task_6]
Rejected:Task_9
PoolSize: 3,Queue[Task_2, Task_3, Task_4, Task_5, Task_6]

代码:

/**
 * 这个例子演示了线程进入线程池的一个流程
 * 线程会先占用核心池,满了之后取队列等待,
 * 队列满了之后,如果还没有达到最大线程数量,继续创建线程。
 */
public class ThreadPoolDemo {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = 
                                   new ThreadPoolExecutor(
                                                2, 3, 2000,
                                                TimeUnit.MILLISECONDS, 
                                                new ArrayBlockingQueue(5), 
                                                new MyRejectedHandler());
        Runnable runTask = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    String name = "Task_" + i;
                    Task task = new Task(name);
                    try {
                        threadPoolExecutor.execute(task);
                        System.out.println(
                            "PoolSize: " + threadPoolExecutor.getPoolSize()+
                                ",Queue"+threadPoolExecutor.getQueue());
                        System.out.println();
                        //Thread.sleep(1000);
                    } catch (Exception e) {
                        System.out.println("Refused:" + name);
                    }
                }

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread thread = new Thread(runTask);
        thread.start();
    }
}
public class Task implements Runnable {
    private String name;
    public Task(String name) {
        this.name = name;
    }
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public String toString() {
        return this.name;
    }
}
// 重写RejectedExecutionHandler
public class MyRejectedHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("Rejected:"+r.toString());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值