【Java进阶】Java线程池ThreadPoolExecutor的使用详解以及SpringBoot下如何使用线程池

1.应用场景

为了使线程池的使用更加的规范,同时合理的规划线程的数量,避免资源消耗。

2.代码理解

下面是ThreadPoolExecutor的构造函数。

    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;
    }

参数的含义介绍

参数含义
corePoolSize指定了线程池中的线程数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去
maximumPoolSize指定了线程池中的最大线程数量
keepAliveTime当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内被销毁
unitkeepAliveTime的单位
workQueue任务队列,被添加到线程池中,但尚未被执行的任务
threadFactory线程工厂,用于创建线程
handler拒绝策略;当任务超出线程池数量时,如何拒绝任务

2.1 workQueue队列

队列类名介绍
直接提交队列SynchronousQueue没有容量,执行一个插入就会阻塞,删除就会唤醒,此时,如果有多条线程任务进来,会直接启用maximumPoolSize对应的线程数量,超出的直接执行拒绝策略
有界的任务队列ArrayBlockingQueue若有新的任务加入线程,线程池会创建新的线程,直到创建的线程达到corePoolSize,再有线程进来,会存在队列当中,如果队列存满,会继续创建线程直到达到maximumPoolSize之后执行拒绝策略
无界的任务队列LinkedBlockingQueue线程池的任务队列可以无限制的添加新的任务,而线程池能够创建的最大的线程数量就是corePoolSize,maximumPoolSize这个参数等于已经无效了
优先任务队列PriorityBlockingQueue在任务中设置优先级,队列会根据优先级进行任务的重排,执行优先级高的任务,任务的执行数量不会超过corePoolSize

2.2 拒绝策略

我们这里只探讨有界队列的情况,因为只有有界队列才可能出现超出队列且超出最大线程数量的情况。

策略含义
AbortPolicy策略该策略会直接抛出异常,阻止系统正常工作
CallerRunsPolicy策略如果线程池的线程数量达到上限,该策略会把任务队列中的任务放在调用者线程当中运行
DiscardOledestPolicy策略该策略会丢弃任务队列中最老的一个任务,也就是当前任务队列中最先被添加进去的,马上要被执行的那个任务,并尝试再次提交
DiscardPolicy策略该策略会默默丢弃无法处理的任务,不予任何处理。当然使用此策略,业务场景中需允许任务的丢失

2.3 自定义线程工厂

public void executeExecutor(){
            new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10), new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r,r.hashCode() + "");
                    return thread;
                }
            },new ThreadPoolExecutor.CallerRunsPolicy());
        }

2.4 自定义拒绝策略

new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10),Executors.defaultThreadFactory(), new RejectedExecutionHandler() {
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println(r.toString()+"执行了拒绝策略"); 
            }
        });

3.SpringBoot下使用线程池

spring-context包下有一个ThreadPoolTaskExcecutor

@Configuration
public class ThreadPoolConfig
{
    // 核心线程池大小
    private int corePoolSize = 10;

    // 最大可创建的线程数
    private int maxPoolSize = 20;

    // 队列最大长度
    private int queueCapacity = 1000;

    // 线程池维护线程所允许的空闲时间
    private int keepAliveSeconds = 300;

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

使用

@Service
public TestServiceImpl implements TestService{

	@Autowird
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;

	public void test(){
		threadPoolTaskExecutor.execute(new Task())
	}

}

还有一个线程池类可能也会用到,就是执行定时任务的线程池ScheduledThreadPoolExecutor
,SpringBoot中注入Bean如下

@Configuration
public class ThreadPoolConfig
{
    // 核心线程池大小
    private int corePoolSize = 50;
/**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService()
    {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build())
        {
            @Override
            protected void afterExecute(Runnable r, Throwable t)
            {
                super.afterExecute(r, t);
                Threads.printException(r, t);
            }
        };
    }
}

用法如下

@Service
public TestServiceImpl implements TestService{

	@Autowird
	private ScheduledExecutorService scheduledExecutorService;

	public void test(){
		scheduledExecutorService.scheduleAtFixedRate(new Task()030,TimeUnit.Seconds);
		// 0表示首次执行任务的延迟时间
		//30表示执行任务的时间间隔
		//TimeUnit.Seconds表示时间的单位
	}

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JeffHan^_^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值