首页 > 其他分享 >一文学会线程池、任务调度的使用

一文学会线程池、任务调度的使用

时间:2022-11-13 22:34:41浏览次数:82  
标签:执行 Runnable 文学 任务 factoryBean 线程 任务调度 public

一文学会线程池、任务调度的使用

本文主要讲解线程池以及定时任务的使用,以及在分布式环境下、JUC线程池和Spring线程池的弊端。

image-20221113205924060

起因:

分布式换环境下的定时任务问题

  • ❓ 有没有可能会出现这个问题,使用JUC或者Spring线程池的话,他们只能配置间隔多长时间执行一次,因为是集群的缘故,他们重复执行,这样有意义吗?

image-20221113210018752

  • ❓ 而Quartz定时任务驱动的参数存到数据库里,通过排队加锁等这样的机制实现共享(也就是同一时间,只有一台服务器执行)

image-20221113210643527

1、JUC线程池

ExecutorService

  • ❗️ 使用步骤:

    1. Executors.newFixedThreadPool(5); 初始化线程池线程数量并构造出ExecutorService
    2. 通过Runnable接口,构造需要执行的内容
    3. 通过ExecutorServicesubmit启动任务
  • ❗️ 具体代码:

  •   private ExecutorService executorService = Executors.newFixedThreadPool(5); // 初始化线程池线程数量
      
      public void testExecutorService() {
          // 线程任务
          Runnable task = new Runnable() {
              @Override
              public void run() {
                  log.debug("HELLO ExecutorService");
              }
          };
          for (int i = 0; i < 10; i++) {
              executorService.submit(task); // 多次执行
          }
          sleep(10); // 防止线程终止
      }
    

ScheduledExecutorService

可执行定时任务的线程池

  • ❗️ 使用步骤:
    1. Executors.newScheduledThreadPool(5) 初始化线程池线程数量并构造出ScheduledExecutorService
    2. 通过Runnable接口,构造需要执行的内容
    3. 通过ScheduledExecutorServicescheduleAtFixedRate启动任务
  • ❗️ 具体代码

scheduledExecutorService还有需要重载的方法:

    /**
     * JDK可执行定时任务的线程池
     */
    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

	public void testScheduleExecutorService() {
        Runnable task = new Runnable() {
            @Override
            public void run() {
                log.debug("HELLO ScheduleExecutorService");
            }
        };
        // 需要执行的任务,第一次延迟多久执行,每个多久执行一次,时间单位
        scheduledExecutorService.scheduleAtFixedRate(task, 1, 1, TimeUnit.SECONDS);
        sleep(10);
    }

2、Spring线程池

注意:

  • Spring线程池的使用需要创建配置文件开启任务调度才可使用,需要初始化ThreadPoolTaskScheduler(线程池任务调度器)
  • image-20221113213206870

ThreadPoolTaskExecutor

  • ❗️ 使用步骤:
    1. application.yaml配置线程池属性 可通过TaskExecutionProperties查看更为详细的配置信息
    2. image-20221113212249574
    3. 注入ThreadPoolTaskExecutor
    4. 通过Runnable接口,构造需要执行的内容
  • ❗️ 具体代码
    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

	public void testThreadPoolTaskExecutor() {
        // 需要执行的任务
        Runnable task = new Runnable() {
            @Override
            public void run() {
                log.debug("HELLO ThreadPoolTaskExecutor");
            }
        };
        for (int i = 0; i < 10; i++) {
            taskExecutor.submit(task);
        }
        sleep(10);
    }

ThreadPoolTaskScheduler

可执行定时任务的线程池

  • ❗️ 使用步骤:

    1. application.yaml配置调度属性,可通过TaskSchedulingProperties查看更为详细的配置信息
    2. image-20221113212601622
    3. 容器中注入ThreadPoolTaskScheduler
    4. 通过Runnable接口,构造需要执行的内容
  • ❗️ 具体代码

  •       // Spring定时任务线程池
          @Resource
          private ThreadPoolTaskScheduler taskScheduler;
      	@Test
      	public void testThreadPoolTaskScheduler() {
              Runnable task = new Runnable() {
                  @Override
                  public void run() {
                      log.debug("HELLO ThreadPoolTaskScheduler");
                  }
              };
              // 需要执行的任务,隔多久执行一次
              taskScheduler.scheduleAtFixedRate(task, 2000);
              sleep(10);
      	}
    

简化使用

你以为不觉得这样的配置过于繁杂了吗,Spring也想到了这点,使用注解的方式来简化使用。

image-20221113213952444

3、Quratz

配置

导入依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

核心概念

  • 任务 Job

    • 我们想要调度的任务都必须实现 org.quartz.job 接口,然后实现接口中定义的 execute() 方法即可,类似于TimerTask
  • 触发器 Trigger

    • Trigger 作为执行任务的调度器。我们如果想要凌晨1点执行备份数据的任务,那么 Trigger 就会设置凌晨1点执行该任务。
    • 其中 Trigger 又分为 SimpleTriggerCronTrigger两种
  • 调度器 Scheduler

    • Scheduler为任务的调度器,它会将任务 Job 及触发器 Trigger整合起来,负责基于 Trigger 设定的时间来执行 Job

image-20221113214533265

使用

使用步骤:

  1. 定义Job
  2. 实例化JobDetailSimpleTigger
  3. (需要持久化到数据库,就得配置)
  • 定义Job 也就是需要执行的内容
@Slf4j
public class AlphaJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.warn(Thread.currentThread().getName()+": execute a quartz job.");
    }
}
  • 实例化JobDetailSimpleTigger
/**
 * 启动项目,将配置信息初始化到数据库中,之后直接访问数据库,
 * 数据库可以被每个实例所获取,从而实现了分布式定时任务
 *
 * @author : look-word
 * 2022-11-13 20:11
 **/
@Configuration
public class QuartzConfig {
    // 配置JobDetail(任务)
    @Bean
    public JobDetailFactoryBean alphaJobDetail() {
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(AlphaJob.class); // 需要被执行的任务
        factoryBean.setName("alphaJob");
        factoryBean.setGroup("alphaJobGroup");
        factoryBean.setDurability(true); // 是否持久化到数据库
        factoryBean.setRequestsRecovery(true); // 当出现问题,是否可恢复
        return factoryBean;
    }

    // 配置 Trigger(触发器)
    @Bean
    public SimpleTriggerFactoryBean alphaTrigger(JobDetail alphaJobDetail) {
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        factoryBean.setJobDetail(alphaJobDetail);
        factoryBean.setName("alphaTrigger");
        factoryBean.setGroup("alphaTriggerGroup");
        factoryBean.setRepeatInterval(3000); // 间隔多久执行
        factoryBean.setJobDataMap(new JobDataMap());
        return factoryBean;
    }
}

配置好上面信息,启动项目,我们的Quratz就是执行了。

如若想要实现持久化到数据,配置下面步骤。

持久化

更为详细的介绍

为什么持久化到数据中

  • 没有配置的都是存储在内存里面的。 当程序突然被中断时,如断电,内存超出时,很有可能造成任务的丢失。 可以将调度信息存储到数据库里面,进行持久化,当程序被中断后,再次启动,仍然会保留中断之前的数据,继续执行,而并不是重新开始。

创建 持久化表

文件地址

持久化到数据库的配置

# quartz 分布式定时任务
spring:
  quartz:
    job-store-type: jdbc
    scheduler-name: communityScheduler
    properties:
      org:
        quartz:
          scheduler:
            instanceId: AUTO  #调度器id自动生成
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX                      # 完成Job持久化配置的类
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate   # 存储使用的JDBC
            isClustered: true                                                   # 是否以集群的方式
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool                            # 使用的线程类
            threadCount: 5														# 线程池的数量
  • 然后再次启动项目,我们对于Quartz的配置,就会持久化到数据库中。

当然,我们的任务持久到数据库中,假如不需要了呢,不可能一个个的去删除吧,那么Quratz也为我们提供了具体的方法。

  • JobKey(配置的任务名称,配置的组名称)
@Resource
private Scheduler scheduler;

@Test
public void testDeleteJob() throws SchedulerException {
    System.out.println(scheduler.deleteJob(new JobKey("alphaJob", "alphaJobGroup")));
}

执行后,会发现持久化到数据库中的信息,被删除了。

标签:执行,Runnable,文学,任务,factoryBean,线程,任务调度,public
From: https://www.cnblogs.com/look-word/p/16887211.html

相关文章

  • 读者-写者(多线程)
     一、同步互斥问题-读者写者问题之写者优先(一)问题要求抽象解释:多个进程访问一个共享的数据区读者(读进程)只能读数据,写者(写进程)只能写数据适用于数据库、文件、内存......
  • 读者-写者(多线程)
    读者-写者(多线程)0推荐在openEuer上实现1描述操作系统中“读者-写者”问题,理解问题的本质,提交你理解或查找到的文本资料2利用多线程完成reader和writer3在main中测......
  • 创建多线程的方法四
    packagedaybyday;/*好处:1.提高相应速度(减少创建新线程的时间)2.降低资源消耗3.便于线程管理corePoolSize核心池的大小maximumPool最大线......
  • 实现多线程的方法三
    packagedaybyday;/*好处:call()可以有返回值call()可以抛出异常,被外面的操作捕获,获取异常的数值Callable是支持泛型的*/importjava.util.concurrent......
  • 读者-写者问题(多线程)
    "读者-写者"问题实现读者和写者问题是一个经典的并发程序设计问题,是经常出现的一种同步问题。所谓读者写者问题,是指保证一个写进程必须与其他进程互斥地访问共享对象的同......
  • 读者-写者(多线程)
    题目1描述操作系统中“读者-写者”问题,理解问题的本质,提交你理解或查找到的文本资料2利用多线程完成reader和writer3在main中测试若干个reader和writer的测试,提交......
  • 读者-写者(多线程)
    任务详情1描述操作系统中“读者-写者”问题,理解问题的本质,提交你理解或查找到的文本资料2利用多线程完成reader和writer3在main中测试若干个reader和writer的测试,......
  • 线程池concurrent.futures
    fromconcurrent.futuresimportThreadPoolExecutor,as_completed,waitimporttime#线程池#主线程中可以获取某一个线程的状态或某一个任务的状态以及返回值#当......
  • 多线程编程学习笔记文章目录
     多线程编程学习笔记-基础(一)多线程编程学习笔记-基础(二)多线程编程学习笔记-基础(三) 多线程编程学习笔记——线程同步(一)多线程编程学习笔记——线程同步(二) 多线......
  • C#多线程之同步基础篇
    目录一、基本概念二、锁构造MonitorMutex死锁三、信号构造SemaphoreManualResetEventAutoResetEventCountdownEvent四、等待句柄等待句柄和线程池WaitHandle一、基本概念......