关于配置执行定时任务和异步任务的线程池配置类

关于配置执行定时任务和异步任务的线程池配置类1
package com.liftsail.rsademo.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.config.Task;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author 张帆
 * @Description 不积跬步无以至千里
 * @Date 2022/11/23 20:50
 */
@Configuration
@Slf4j
public class ThreadPoolConfig implements AsyncConfigurer, SchedulingConfigurer {

    /**
     * 异步任务执行线程池参数
     */
    private static final Integer CORE_POOL_SIZE = 5;
    private static final Integer MAX_POOL_SIZE = 200;
    private static final Integer QUEUE_CAPACITY = 2000;
    private static final String THREAD_NAME_PREFIX = "async-thread-";
    private static final Integer KEEP_ALIVE_SECONDS = 60;

    /**
     * 定时任务线程池线程名前缀
     */
    private static final String SCHEDULER_THEREAD_NAME_PREFIX = "task-";

    /**
     * @param
     * @description: 创建执行spring task定时任务的线程池,调用@scheduled注解的定时任务
     * @author: xiaomifeng1010
     * @date: 2022/3/13
     * @return: TaskScheduler
     **/
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(10);
        threadPoolTaskScheduler.setThreadNamePrefix(SCHEDULER_THEREAD_NAME_PREFIX);
        threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        return threadPoolTaskScheduler;
    }

    /**
     * @param
     * @description: 创建执行异步任务的线程池,用于调用 @async注解的方法
     * @author: xiaomifeng1010
     * @date: 2022/3/13
     * @return: ThreadPoolTaskExecutor
     **/
    @Bean("asyncThreadPoolTaskExecutor")
    public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        // 核心线程数量
        threadPoolTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        // 最大线程数量
        threadPoolTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        // 队列中最大任务数
        threadPoolTaskExecutor.setQueueCapacity(QUEUE_CAPACITY);
        // 线程名称前缀
        threadPoolTaskExecutor.setThreadNamePrefix(THREAD_NAME_PREFIX);
        // 当达到最大线程数时如何处理新任务(拒绝策略)
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 线程空闲后最大存活时间
        threadPoolTaskExecutor.setKeepAliveSeconds(KEEP_ALIVE_SECONDS);
        // 初始化线程池
        threadPoolTaskExecutor.initialize();
        // 关闭线程池
        threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        return threadPoolTaskExecutor;
    }

    /**
     * Callback allowing a {@link TaskScheduler
     * TaskScheduler} and specific {@link Task Task}
     * instances to be registered against the given the {@link ScheduledTaskRegistrar}.
     *
     * @param taskRegistrar the registrar to be configured.
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setTaskScheduler(threadPoolTaskScheduler());
    }

    /**
     * The {@link Executor} instance to be used when processing async
     * method invocations.
     */
    @Override
    public Executor getAsyncExecutor() {
        return asyncThreadPoolTaskExecutor();
    }

    /**
     * The {@link AsyncUncaughtExceptionHandler} instance to be used
     * when an exception is thrown during an asynchronous method execution
     * with {@code void} return type.
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (throwable, method, objects) -> {
            log.error("异步任务执行出现异常, message {}, method {}, params {}", throwable, method, objects);
        };
    }
}
@Scheduled和@Async在spring-boot中共享相同的线程池

我已经配置了两个不同的线程池,一个用于@Scheduled和另一个用于@Async.但是,我注意到@Async没有使用线程池.

这是Scheduler配置

@Configuration
@EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {
    private final int POOL_SIZE = 10;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
        threadPoolTaskScheduler.setThreadNamePrefix("my-sched-pool-");
        threadPoolTaskScheduler.initialize();
        scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
    }
}
这是Async的配置

@Configuration
@EnableAsync
public class AppConfig {

 @Bean(name = "asyncTaskExecutor")
    public TaskExecutor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(15);
        executor.setMaxPoolSize(15);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("my-async-pool-");
        executor.initialize();
        return executor;
    }
}
这是我如何调用它们

@Scheduled(fixedRateString = "2000" )
    public void schedule() {
      log.debug("here is the message from schedule");
      asyncMethod();
    }

@Async("asyncTaskExecutor")
public void asyncMethod(){
  log.info("here is the message from async");
}
这是日志

{"thread":"my-sched-pool-1","level":"DEBUG","description":"here is the message from schedule"}
{"thread":"my-sched-pool-1","level":"INFO","description":"here is the message from async"}
您可以注意到,两个日志都具有该调度程序的相同池.但我希望看到第二个来自异步.

如果你声明它们被声明的@Async方法,class你实际上绕过了Spring的代理机制,这就是为什么你的例子不起作用的原因.尝试从单独class注释的方法@Service或任何其他@Component类型调用该方法.

@Service
SomeScheduledClass {

  private final SomeAsyncClass someAsyncClass;

  public SomeScheduledClass(SomeAsyncClass someAsyncClass) {
    this.someAsyncClass = someAsyncClass;
  }

  @Scheduled(fixedRateString = "2000" )
  public void schedule() {
    log.debug("here is the message from schedule");
    someAsyncClass.asyncMethod();
  }
}

@Service
SomeAsyncClass {
  @Async("asyncTaskExecutor")
  public void asyncMethod(){
    log.info("here is the message from async");
  }
}
异步线程池与定时任务线程池
两个线程池都是一样的步骤:

第一步是线程池配置;

第二步写具体定时或异步任务。

先看异步线程池:

package com.xnpool.common.async;
 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
 
@Configuration
@EnableAsync  // 启用异步任务
public class AsyncConfiguration {
    @Value("${asynctask.corepoolsize}")
    private int corepoolsize;
    @Value("${asynctask.maxpoolsize}")
    private int maxpoolsize;
    @Value("${asynctask.queuecapacity}")
    private int queuecapacity;
    @Value("${asynctask.keepaliveseconds}")
    private int keepaliveseconds;
    @Value("${asynctask.threadnameprefix}")
    private String threadnameprefix;
    @Value("${asynctask.waitfortaskstocompleteonshutdown}")
    private boolean waitfortaskstocompleteonshutdown;
    @Value("${asynctask.awaitterminationseconds}")
    private int awaitterminationseconds;
 
    // 声明一个线程池(并指定线程池的名字)
    @Bean("taskExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数5:线程池创建时候初始化的线程数
        executor.setCorePoolSize(corepoolsize);
        //最大线程数5:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(maxpoolsize);
        //缓冲队列500:用来缓冲执行任务的队列
        executor.setQueueCapacity(queuecapacity);
        //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(keepaliveseconds);
        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix(threadnameprefix);
        /*
         * 线程池对拒绝任务(无线程可用)的处理策略
         * AbortPolicy:丢弃任务,直接抛出java.util.concurrent.RejectedExecutionException异常,默认的策略
         * CallerRunsPolicy:这个策略重试添加当前的任务,他会自动重复调用 execute() 方法,直到成功
         * DiscardOldestPolicy: 丢弃队列最前面的任务,然后重新尝试执行任务,会导致被丢弃的任务无法再次被执行
         * DiscardPolicy:抛弃当前任务;会导致被丢弃的任务无法再次被执行,但是不抛出异常
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(waitfortaskstocompleteonshutdown);
        executor.setAwaitTerminationSeconds(awaitterminationseconds);
        executor.initialize();
        return executor;
    }
 
}
启用了线程异步任务后,就可以写代码了:

package com.xnpool.common.async;
 
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xnpool.common.constant.AuthConstant;
import com.xnpool.common.mapper.ds1.CCoinMapper;
import com.xnpool.common.mapper.ds1.SubuserMapper;
import com.xnpool.common.mapper.ds2.UserAddressMapper;
import com.xnpool.common.model.CommonCoin;
import com.xnpool.common.model.Subuser;
import com.xnpool.common.model.UserAddress;
import com.xnpool.common.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
 
import java.util.*;
import java.util.stream.Collectors;
 
@Slf4j
@Service
public class AsyncTaskService {
    @Autowired
    private UserAddressMapper userAddressMapper;
    @Autowired
    private TableUtil tableUtil;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private CCoinMapper coinMapper;
    @Autowired
    private SubuserMapper subuserMapper;
    @Autowired
    private RedisService redisService;
 
 
 
    /**
     *
     * @param pid 企业id
     * @param aid 应用id
     * @param uid 用户id
     * @param cid 子账号id
     */
    @Async("taskExecutor")//指定了异步线程池名
    public void executeAsyncTask(Long pid,Long aid, String uid, String cid,boolean b) {
        String sql="select coin_id as coinId,coin_name as coinName,price,contract_coin_id as contractCoinId,contract_coin as contractCoin from t_coin";
        /*//查询币种列表  new BeanPropertyRowMapper<CommonCoin>(CommonCoin.class)*/
        //BeanPropertyRowMapper<CommonCoin> rowMapper = new BeanPropertyRowMapper<CommonCoin>(CommonCoin.class);
        List<CommonCoin> coinIds =coinMapper.selectList(new QueryWrapper<CommonCoin>());
        ArrayList<UserAddress> userAddressArrayList = new ArrayList<UserAddress>();
 
        String existsAddress = tableUtil.isExistsAddress(pid);//一个企业一个用户币种关联表。(没有表就先创建)
        log.info("增加用户或子账户的币种地址============");
        if (existsAddress != null && userAddressArrayList.size()>0) {
            userAddressMapper.insertCoinBase(existsAddress, userAddressArrayList);
        }
    }
 
    @Async("taskExecutor")//指定了异步线程池名
    public void executeAsyncCoinTask(Integer coinId, String coinName,Integer isContact, Integer contactCoinId) {
        List<Subuser> ulist=subuserMapper.findAllSubList();
        if(CollectionUtil.isNotEmpty(ulist)){
            Map<Long,List<Subuser>> map=ulist.stream().filter(u->u.getEnterpriseId()!=null).collect(Collectors.groupingBy(Subuser::getEnterpriseId));
            Long platId=getPalateFromId();
 
                String existsAddress = tableUtil.isExistsAddress(pid);//一个企业一个用户币种关联表。(没有表就先创建)
                log.info("增加用户或子账户的币种地址============");
                if (existsAddress != null && userAddressArrayList.size()>0) {
                    userAddressMapper.insertCoinBase(existsAddress, userAddressArrayList);
                }
            }
 
        }
 
    }
 
}
下面贴定时任务线程池:

package com.xnpool.admin.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
 
import java.util.concurrent.Executor;
 
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskScheduleExecutor());
    }
 
    @Bean(destroyMethod="shutdown")
    public Executor taskScheduleExecutor() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(10);
        scheduler.setThreadNamePrefix("schedule_task-");
        scheduler.setAwaitTerminationSeconds(600); 线程池关闭前最大等待时间,确保最后一定关闭
        scheduler.setWaitForTasksToCompleteOnShutdown(true);// 线程池关闭时等待所有任务完成
        return scheduler;
        //return Executors.newScheduledThreadPool(10); //指定线程池大小
    }
}
 
具体使用定时任务的地方:

@Slf4j
@Service
public class SendMessageService {
    @Autowired
    private PushUtil pushUtil;
 
    @Autowired
    private TransactionMapper transactionsMapper;
    @Autowired
    private TUserMapper userMapper;
 
    @Autowired
    private TCoinMapper coinMapper;
 
    @Autowired
    private TNoticeMapper noticeMapper;
    @Autowired
    private TMessageMapper messageMapper;
    @Autowired
    private TableUtil tableUtil;
 
    @Autowired
    private RedisService redisService;
 
 
    /**
     * 推送公告(把公告推送给所有手机用户,推送后,不管用户是否接收,公告状态改为已发送状态)
     */
    @Scheduled(fixedDelay = 1000 * 60 * 5)
    public void sendNotice() {
        List<TNotice> notices = noticeMapper.selectList(new QueryWrapper<TNotice>().lambda().eq(TNotice::getIsSend,0));
        if (notices != null && notices.size() > 0) {
            List<Integer> idList = notices.stream().map(TNotice::getId).collect(Collectors.toList());
            List<TUser> userList = userMapper.selectClientList();
            List<String> clinetList=userList.stream().map(TUser::getClientid).collect(Collectors.toList());
            
 
        }
    }
 
    /**
     * 推送消息(将所有状态是已完成未发送的交易,发送给用户。 发送完就把状态改成已发送。)
     */
    @Scheduled(fixedDelay = 1000 * 10)
    public void sendTx() {
        }

}

这两个定时任务没有指定线程池名字,但已确认它是在线程池ScheduleConfig 中。

 

posted @ 2022-11-23 20:49  liftsail  阅读(199)  评论(0编辑  收藏  举报