Java 调度

Rashmi Patidar 2023年1月30日 2021年10月2日
  1. 使用 Java 中的 ScheduledExecutorService 接口方法调度进程
  2. 使用 Java 中的 Timer 类调度线程
Java 调度

调度是以固定的时间间隔执行任务或功能的过程。调度在运行批处理、发送基于事件的触发器(如生日祝福)、发送推送通知中找到了它的用途。这些过程必须根据给定的条件和时间间隔在明确定义的时间运行。

使用 Java 中的 ScheduledExecutorService 接口方法调度进程

package scheduling;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class ScheduleTask {
    private static int counter = 0;

    public static void main(String[] args) throws InterruptedException {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
        Runnable executeTask = () -> {
            counter++;
            System.out.println("Task" + counter);
        };

        ScheduledFuture<?> scheduleAtFixedRate = service.scheduleAtFixedRate(executeTask, 5, 1, TimeUnit.SECONDS);

        while (true) {
            Thread.sleep(1000);
            if (counter == 5) {
                System.out.println("Stopping the scheduled task!");
                scheduleAtFixedRate.cancel(true);
                service.shutdown();
                break;
            }
        }
    }
}

在上面的代码中,首先,一个静态计数器变量被初始化为零值。newScheduledThreadPoolExecutors 类的静态方法。该方法创建一个线程池,该线程池应该使用参数列表中给出的参数定期执行。所以在我们的例子中,创建了一个线程来执行,因为方法参数列表中的参数定义了线程池的数量。该方法返回一个 ScheduledExecutorService 实例,该实例存储在 service 引用变量中,如果池大小小于零,则抛出 IllegalArgumentException

Runnable 是一个任何类都可以扩展的接口,并且是功能性接口。它只有一个静态方法作为 run 方法,供线程执行。使用表示为符号 ()-> 括号和箭头的 lambda 表达式,该结构表明我们没有将任何参数传递给 run 方法。我们已经在 run 方法的定义中定义了语句。块内的语句将增加计数器变量并在控制台输出中打印任务。这些所有语句都由名为 executeTask 变量的变量引用。

service 引用变量调用 ScheduledExecutorService 接口的 scheduleAtFixedRate 方法。该方法创建并执行应该在初始延迟之后和给定时间段内稍后执行的周期性任务。它需要四个参数,一个应该执行的 runnable 命令,initialDelay 变量是延迟第一次执行的时间,period 表示连续执行之间的持续时间,而 unit 是时间单位,以秒为单位、分钟和小时。一旦方法被调用,线程就开始执行。

在 while 循环中,首先强制当前运行的线程休眠。Thread.sleep() 方法在定义的时间内暂时停止当前正在执行的线程。该参数是当前工作线程应该停止的毫秒数。如果值为负,则该方法抛出 IllegalArgumentException,如果当前线程被中断,则抛出 InterruptedException。稍后使用定义的值检查计数器的值。此检查用于运行 while 方法一定次数。否则,该块将运行一个永远不会终止的无限数。在 while 块中,scheduleAtFixedRate 变量调用 cancel 方法,该方法取消线程的当前执行。该函数还接受一个布尔参数,指示当前正在运行的线程是否可以中断。

service.shutdown 方法启动关闭过程,在该过程中应该执行先前提交的任务,并且不接受任何新任务。

上述代码块的输出如下。

Task1
Task2
Task3
Task4
Task5
Stopping the scheduled task!

使用 Java 中的 Timer 类调度线程

下面是使用其构造函数实例化两个用户定义的类对象的简单代码块。TimerImplementation 是用户定义的类。创建了一个 Timer 实例,它将创建一个新线程。然后新创建的计时器对象将调用 scheduleAtFixedRate 方法。该方法将参数作为需要调度的任务延迟以毫秒为单位延迟任务,而周期是以毫秒为单位连续执行的时间。

package timer;

import java.util.Timer;

public class UsingTimerClass {
    public static void main(String[] args) {
        TimerImplementation timer1 = new TimerImplementation("Thread1");
        TimerImplementation timer2 = new TimerImplementation("Thread2");

        Timer t = new Timer();
        t.scheduleAtFixedRate(timer1, 0, 2000);
        t.scheduleAtFixedRate(timer2, 0, 1000);
    }
}

下面是用户定义类的实现。TimerImplementation 类扩展了 TimerTask 抽象类,该抽象类包含一个名为 run 的抽象方法。我们在用户定义的类中扩展 TimerTask 类,然后覆盖 run 方法。

该类具有一个用户定义的构造函数,用于将用户定义的名称设置为线程对象。

我们可以在线程 run 方法中给出实际的逻辑。它包括一个作为 print 的语句,它将打印当前正在执行的线程的名称。Thread.currentThread().getName() 返回当前执行线程的名称。sleep 方法通过 Thread1 调用,中断执行 1000 毫秒。如果任何线程中断当前线程,sleep 方法会抛出 InterruptedException,这就是它被包含在 try-catch 块中的原因。

package timer;

import java.util.TimerTask;

public class TimerImplementation extends TimerTask {

    private String name;

    public TimerImplementation(String n) {
        this.name = n;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " " + name);
        if ("Thread1".equalsIgnoreCase(name)) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

以下是上述代码的永无止境的输出。由于我们没有在 run 方法中定义任何终止条件,线程将无休止地执行,直到应用外部停止来终止主线程的执行。

Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2
Rashmi Patidar avatar Rashmi Patidar avatar

Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.

LinkedIn