自建线程池的参数介绍和spring启动类配置线程池执行定时任务


线程池中ThreadPoolExecutor构造器有7个参数,如下所示。

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

一、线程池的作用

1.减少资源的开销
2.减少了每次创建线程、销毁线程的开销
3.提高了响应速度
每次请求到来时,由于线程的创建已经完成,故可以直接执行任务,因此提高了响应速度。
提高线程的可管理行,线程是一种稀缺资源,若不加以限制,不仅会占用大量资源,而且会影响系统的稳定性
因此,线程池可以对线程的创建和停止、线程数量等等因素加以控制,使得线程在一种可控的范围运行,不仅能保证系统稳定运行,而且方便性能调优。

二、自建线程池的参数介绍

1. corePoolSize

核心池大小corePoolSize:表示线程池维护线程的最少数量

2. maximumPoolSize

最大池大小maximumPoolSize:表示线程池维护线程的最大数量

3. workQueue

阻塞队列workQueue:表示如果任务数量超过核心池大小,多余的任务添加到阻塞队列中

4. corePoolSize、workQueue、maximumPoolSize的关系

前提假设:向线程池每添加一个任务就sleep。也就是说假设任务数与线程数一一对应,每添加一个任务就对应的创建一个线程,并且一直等待其他线程。
因为可能某一个线程执行了两个任务,看不出效果。

a.
 if 任务数 <= 核心池大小 
 则每添加一个任务就会创建一个线程来执行该任务,线程最大数量等于核心池大小
b.
 if 任务数 > 核心池大小 && 任务数 <= 核心池大小 + 阻塞队列大小
 则线程数量等于核心池大小,其余任务放入到阻塞队列中
c.
if 任务数 > 核心池大小 + 阻塞队列大小 && 任务数 <= 最大池大小
则会创建新的线程来处理新的任务
d.
  if 任务数 > 最大池大小
  则会采用拒绝策略handler

5. 参数keepAliveTime

6. 参数unit

7. 参数threadFactory

8. 参数handler

keepAliveTime: 线程池维护线程所允许的空闲时间
unit: 线程池维护线程所允许的空闲时间的单位
handler: 线程池对拒绝任务的处理策略

Executor

9.实例

ExecutorService fixedThreadPool = new ThreadPoolExcutor(3,10,0LTimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());

三、spring启动类配置线程池执行定时任务

1.启动类增肌@EnableAsync注解。可识别异步注解

在这里插入图片描述

2.启动类配置线程池,以支持异步执行定时任务

@Bean(name = "scheduledAsyncPoolExecutor")
public ThreadPoolTaskExecutor getAsyncPoolPoolTaskExecutor(){
	ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
	//线程池维护先吃的最少数量,定时任务通常同一时间执行的不会超过3个
	taskExecutor.setCorePoolSize(3);
	//线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程
	taskExecutor.setMaxPoolSize(30);
	//缓冲队列,定时任务需要及时执行,不能进行缓存,否则获得锁会有问题
	taskExecutor.setQueueCapacity(0);
	//允许的空闲时间,当超过了核心线程数之外的线程在空闲时间达到之后会被销毁
	taskExecutor.setKeepAliveSeconds(60);
	//设置线程的前缀名
	taskExecutor.setThreadNamePrefix("scheduled-");
	taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
	taskExecutor.initialize();
	return taskExecutor;
}

3.定时任务service类的代码

@Service
public class ScheduledScanningService {
//每天凌晨执行一次任务
@Scheduled(cron = "${query.loan.custInfo.result:0 0 4 * * ?}")
@Async("scheduledAsyncPoolExecutor")//异步执行任务,value值为配置的线程池
public void scheduledQueryLoanAndCustInfo() {
    //项目部署至多台服务器上,使用redis锁,只需一台服务器执行即可
    String lockId = "redis_lock_key";
    //获得redis锁
    Long canRun = getRedisLock(lockId, String.valueOf(System.currentTimeMillis()), "600");
    String ip = getServiceIP();
    //将redis锁标识,redis锁,拿到redis锁的时间,拿到redis锁服务器的ip记录至mongo日志中
    addLogScheduledBymongolog(lockId, String.valueOf(canRun), System.currentTimeMillis(), ip);
}

四、Java中自带的线程池介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、线程池的代码

    
    private volatile ThreadPoolExecutor consumerPool;
    
    //异步线程池
    @PostConstruct
    private void init(){
    //最大线程数设置与CPU一致
    //参数依次为:核心线程数、最大线程数、等待时间、时间单位、队列长度、策略
        consumerPool = new ThreadPoolExecutor(1,4,5L, 
                TimeUnit.MINUTES,new LinkedBlockingDeque<>(5000*2),new ThreadPoolExecutor.DiscardPolicy());
                //JVM之前销毁线程池
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                consumerPool.shutdown();
            }
        }));
    }

五、CountDownLatch对异步线程进行收束

 public static void main(String[] args) throws InterruptedException {
        //设置线程个数
        CountDownLatch latch = new CountDownLatch(3);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    latch.countDown();
                }
                latch.countDown();
                System.out.println("第一个线程");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    //执行完后,减一
                    latch.countDown();
                }
                latch.countDown();
                System.out.println("第二个线程");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10);
                    System.out.println("第三个线程");
                } catch (InterruptedException e) {
                    //执行完后,减一
                    latch.countDown();
                }
                latch.countDown();

            }
        }).start();
        //可进行线程的收束,异常线程完后减数,立刻唤起主线程执行
        //否则最多阻塞2分钟,主线程执行
        latch.await(2,TimeUnit.MINUTES);
        System.out.println("结束。。。");
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值