ITPub博客

首页 > 应用开发 > Html/css > 如果你看过一些定时任务框架的源码,你最后会发现,它们的底层

如果你看过一些定时任务框架的源码,你最后会发现,它们的底层

投稿 Html/css 作者:ecclw459 时间:2026-01-26 17:09:49 0 删除 编辑

  new Thread (() -> {         while ( true ) {             try {                System.out.println( "下载文件" );                Thread.sleep( 1000 * 60 * 5 );            } catch (Exception e) {                log.error(e);            }

注意的地方是,需要用 try...catch捕获异常,否则如果出现异常,就直接退出循环,下次将无法继续执行了。

但这种方式做的定时任务,只能周期性执行,不能支持定时在某个时间点执行。

特别提醒一下,该线程建议定义成 守护线程,可以通过 setDaemon方法设置,让它在后台默默执行就好。

使用场景:比如项目中有时需要每隔5分钟去 下载某个文件,或者每隔10分钟去读取模板文件 生成静态html页面等等,一些简单的周期性任务场景。

使用 Thread类做定时任务的优缺点:

  • 优点:这种定时任务非常简单,学习成本低,容易入手,对于那些简单的周期性任务,是个不错的选择。

  • 缺点:不支持指定某个时间点执行任务,不支持延迟执行等操作,功能过于单一,无法应对一些较为复杂的场景。



    private volatile boolean running = false ;     private Thread thread;     @Autowired     private CanalConnector canalConnector;         public void handle () {         //连接canal         while (running) {           //业务处理        }    }         public void start () {       thread = new Thread ( this ::handle, "name" );       running = true ;       thread.start();    }         public void stop () {       if (!running) {           return ;


@Autowired     private CanalService canalService;     @ApolloConfigChangeListener     public void change (ConfigChangeEvent event) {         String value = event.getChange( "test.canal.enable" ).getNewValue();         if (BooleanUtils.toBoolean(value)) {            canalService.start();        } else {

private static final int QUEUE_MAX_SIZE     = 1000 ;     private BlockingQueueblockingQueue queue = new LinkedBlockingQueue <>(QUEUE_MAX_SIZE);     //生成消息     public boolean push (LoginLog loginLog) {         return this .queue.add(loginLog);    }     //消费消息     public LoginLog poll () {         LoginLog loginLog = null ;         try {            loginLog = this .queue.take();        } catch (InterruptedException e) {


    @Autowired     private LoginLogQueue loginLogQueue;     public int login (UserInfo userInfo) {         //业务处理         LoginLog loginLog = convert(userInfo);ttkqgw.cn


@Autowired     private LoginLogQueue queue;     @PostConstruct     public voit init {       new Thread (() -> {           while ( true ) {               LoginLog loginLog = queue.take();


  CompletableFuture userFuture = CompletableFuture.supplyAsync(() -> {        getRemoteUserAndFill(id, userInfo);         return Boolean.TRUE;    }, executor);     CompletableFuture bonusFuture = CompletableFuture.supplyAsync(() -> {        getRemoteBonusAndFill(id, userInfo);         return Boolean.TRUE;    }, executor);     CompletableFuture growthFuture = CompletableFuture.supplyAsync(() -> {        getRemoteGrowthAndFill(id, userInfo);         return Boolean.TRUE;    }, executor);    CompletableFuture.allOf(userFuture, bonusFuture, growthFuture).join();    userFuture.get();    bonusFuture.get();    growthFuture.get();ttzb.gs.cn     return userInfo;


  private static final TransmittableThreadLocal<CurrentUser> THREA_LOCAL = new TransmittableThreadLocal <>();         private String id;     private String userName;     private String password;     private String phone;    ...         public statis void set (CurrentUser user) {      THREA_LOCAL.set(user);    }         public static void getCurrent () {


public class UserInterceptor extends HandlerInterceptorAdapter {     @Override     public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {       CurrentUser user = getUser(request);       if (Objects.nonNull(user)) {


private BusinessConfig businessConfig; CurrentUser user = CurrentUser.getCurrent(); if (Objects.nonNull(user)) {   entity.setUserId(user.getUserId());   entity.setUserName(user.getUserName()); } else {   entity.setUserId(businessConfig.getDefaultUserId());   entity.setUserName remenzhibo.net(businessConfig.getDefaultUserName());

此外,众所周知, SimpleDateFormat在java8以前,是用来处理时间的工具类,它是非线程安全的。也就是说,用该方法解析日期会有线程安全问题。

为了避免线程安全问题的出现,我们可以把SimpleDateFormat对象定义成 局部变量。但如果你一定要把它定义成静态变量,可以使用ThreadLocal保存日期,也能解决线程安全问题。

8. 传递参数

之前见过有些同事写代码时,一个非常有趣的用法,即:使用 MDC传递参数。

MDC是什么?

MDC是 org.slf4j包下的一个类,它的全称是 Mapped Diagnostic Context,我们可以认为它是一个线程安全的存放诊断日志的容器。

MDC的底层是用了 ThreadLocal来保存数据的。

例如现在有这样一种场景:我们使用 RestTemplate调用远程接口时,有时需要在 header中传递

@Override     public void init (FilterConfig filterConfig) throws ServletException {    } espnzhibo.cn    @Override nbczhibo.com     public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        MdcUtil.add(UUID.randomUUID().toString());        System.out.println( "记录请求日志" );        chain.doFilter(request, response);        System.out.println( "记录响应日志" );    }     @Override


    @Bean     public RestTemplate restTemplate () {         RestTemplate restTemplate = new RestTemplate ();        restTemplate.setInterceptors(Collections.singletonList(restTemplateInterceptor()));         return restTemplate;    }     @Bean     public RestTemplateInterceptor restTemplateInterceptor () {         return new RestTemplateInterceptor ();

  private static final String TRACE_ID = "TRACE_ID" ; nbczhibo.com    public static String get () {         return MDC.get(TRACE_ID);    }     public static void add (String value) {


 */     final AtomicInteger atomicInteger = new AtomicInteger ( 0 );     final CountDownLatch countDownLatch = new CountDownLatch ( 1000 ); // 相当于计数器,当所有都准备好了,再一起执行,模仿多并发,保证并发量     final CountDownLatch countDownLatch2 = new CountDownLatch ( 1000 ); // 保证所有线程执行完了再打印atomicInteger的值     ExecutorService executorService = Executors.newFixedThreadPool( 10 );     try {         for ( int i = 0 ; i < 1000 ; i++) {            executorService.submit( new Runnable () {                 @Override                 public void run () {                     try {                        countDownLatch.await();footzhibo.cn //一直阻塞当前线程,直到计时器的值为0,保证同时并发                    } catch (InterruptedException e) {                        log.error(e.getMessage(),e);                    }                     //每个线程增加1000次,每次加1                     for ( int j = 0 ; j < 1000 ; j++) {                        atomicInteger.incrementAndGet();                    }                    countDownLatch2.countDown();                }            });            countDownLatch.countDown();        }        countDownLatch2.await(); // 保证所有线程执行完


  private int corePoolSize;     @Value("${thread.pool.maxPoolSize:10}")     private int maxPoolSize;     @Value("${thread.pool.queueCapacity:200}")     private int queueCapacity;     @Value("${thread.pool.keepAliveSeconds:30}")     private int keepAliveSeconds;     @Value("${thread.pool.threadNamePrefix:ASYNC_}")     private String threadNamePrefix;     @Bean("messageExecutor")     public Executor messageExecutor () ttzbw.org.cn{  ftzhibo.com       ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor ();        executor.setCorePoolSize(corePoolSize);        executor.setMaxPoolSize(maxPoolSize);        executor.setQueueCapacity(queueCapacity);        executor.setKeepAliveSeconds(keepAliveSeconds);        executor.setThreadNamePrefix(threadNamePrefix);        executor.setRejectedExecutionHandler( new ThreadPoolExecutor .C

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048957/viewspace-3109010/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2026-01-07

  • 博文量
    108
  • 访问量
    102113