【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时,多余的线程会在多长时间内被销毁
unit keepAliveTime的单位
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表示时间的单位
	}

}
posted @   JeffHan  阅读(517)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示