+2

Hướng dẫn Lập lịch Công việc tự động trong Java Core

Giới thiệu

Trong lập trình ứng dụng, việc lập lịch các tác vụ tự động là một phần quan trọng để thực thi các hành động định kỳ hoặc theo thời gian nhất định. Trong Java, chúng ta có thể sử dụng ScheduledExecutorService để thực hiện điều này một cách dễ dàng và hiệu quả.

Ví dụ minh họa

Dưới đây là mã nguồn của một lớp Scheduled ,RunnerTest để lập lịch và quản lý các công việc tự động:

Scheduled.java

package com.amb.config.automatic;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

public class Scheduled {
    private ScheduledExecutorService scheduler;
    public static List<Map<String, ScheduledFuture<?>>> scheduledTasks;

    public Scheduled() {
        this.scheduler = Executors.newScheduledThreadPool(1);
        scheduledTasks = new ArrayList<>();
    }

    public ScheduledFuture<?> execute(String className, String submitTime) throws ParseException {
        long delay = calculateDelay(submitTime);
        Map<String, ScheduledFuture<?>> mapJob = new HashMap<>();
        ScheduledFuture<?> scl = scheduler.schedule(new Task(className, "execute", submitTime), delay, TimeUnit.MILLISECONDS);
        if (mapJob.get(className) == null) {
            mapJob.put(className, scl);
        }
        scheduledTasks.add(mapJob);
        return scl;
    }

    public void cancelAllTasks() {
        for (Map<String, ScheduledFuture<?>> future : scheduledTasks) {
            for (ScheduledFuture<?> sf : future.values()) {
                sf.cancel(false);
            }
        }
        scheduledTasks.clear();
        scheduledTasks = new ArrayList<>();
    }

    public void pauseTask(String className) {
        for (Map<String, ScheduledFuture<?>> future : scheduledTasks) {
            ScheduledFuture<?> sf = future.get(className);
            if (sf != null) {
                sf.cancel(false);
                System.out.println("Task paused: " + className);
            }
        }
    }

    public void resumeTask(String className, String submitTime) throws ParseException {
        for (Map<String, ScheduledFuture<?>> future : scheduledTasks) {
            ScheduledFuture<?> sf = future.get(className);
            if (sf != null) {
                long remainingDelay = sf.getDelay(TimeUnit.MILLISECONDS);
                sf.cancel(false);
                long delay = calculateDelay(submitTime) + remainingDelay;
                ScheduledFuture<?> newSf = scheduler.schedule(new Task(className, "resumeTask", submitTime), delay, TimeUnit.MILLISECONDS);
                future.put(className, newSf);
                System.out.println("Task resumed: " + className);
            }
        }
    }

    public void stopTask(String className) {
        Iterator<Map<String, ScheduledFuture<?>>> iterator = scheduledTasks.iterator();
        while (iterator.hasNext()) {
            Map<String, ScheduledFuture<?>> futureMap = iterator.next();
            ScheduledFuture<?> sf = futureMap.get(className);
            if (sf != null) {
                sf.cancel(true);
                iterator.remove(); // Loại bỏ mục khỏi danh sách
                System.out.println("Task stopped: " + className);
            }
        }
    }

    private long calculateDelay(String submitTime) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = dateFormat.parse(submitTime);
        return Math.max(0, date.getTime() - System.currentTimeMillis());
    }

    private class Task implements Runnable {
        private String className;
        private String action;
        private String submitTime;

        public Task(String className, String action, String submitTime) {
            this.className = className;
            this.action = action;
            this.submitTime = submitTime;
        }

        @Override
        public void run() {
            try {
                Class<?> clazz = Class.forName(className);
                Object instance = clazz.getDeclaredConstructor().newInstance();
                Method executeMethod = clazz.getMethod("execute", String.class);
                Object result = executeMethod.invoke(instance, clazz.getName());
                System.out.println(result);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

Runner.java

package com.amb.config.automatic;

import java.text.SimpleDateFormat;
import java.util.Date;

public abstract class Runner {
    private int returnCode;
    private String returnMessage;

    public int getReturnCode() {
        return returnCode;
    }

    public void setReturnCode(int returnCode) {
        this.returnCode = returnCode;
    }

    public String getReturnMessage() {
        return returnMessage;
    }

    public void setReturnMessage(String returnMessage) {
        this.returnMessage = returnMessage;
    }

    public abstract void run() throws Exception;

    public Runner execute(String className) {
        try {
            this.returnCode = 0;
            Class<?> clazz = Class.forName(className);
            log("JobName: [" + clazz.getSimpleName() + "] is Run");
            run();
            log("JobName: [" + clazz.getSimpleName() + "] is Done");
        } catch (Exception e) {
            this.returnCode = -1;
            this.returnMessage = e.getMessage();
            log("Job ClassName: " + className + " is ERROR");
            e.printStackTrace();
        }
        return this;
    }

    protected String timeLog() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return dateFormat.format(new Date());
    }

    protected void log(String message) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String currentTime = dateFormat.format(new Date());
        System.out.println(currentTime + " - " + message);
    }
}

Test.java


public class Test extends Runner {
    public void run() throws Exception {
        System.out.println("Hello");
    }

    public static void main(String[] args) {
        Scheduled e1 = new Scheduled();
        try {
            ScheduledFuture<?> future = e1.execute("com.amb.config.automatic.Test", "2024-05-22 10:30:00");
            System.out.println(future.isDone());
            e1.pauseTask("com.amb.config.automatic.Test");
            e1.stopTask("com.amb.config.automatic.Test");
            Thread.sleep(2000); // Sleep for 2 seconds
            e1.resumeTask("com.amb.config.automatic.Test", "2024-05-22 10:30:00");
            Thread.sleep(2000); // Sleep for 2 seconds
            e1.stopTask("com.amb.config.automatic.Test");
            e1.repeatTask("com.amb.config.automatic.Test", "2024-05-22 10:30:00", 10, TimeUnit.SECONDS);
            //e1.repeatMinutely("com.amb.config.automatic.Test", "2024-05-22 10:30:00");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Kết quả:

false
Task paused: com.amb.config.automatic.Test
Task stopped: com.amb.config.automatic.Test
2024-07-11 14:45:12 - JobName: [Test] is Run
Hello
2024-07-11 14:45:12 - JobName: [Test] is Done
com.amb.config.automatic.Test@4519cdba
2024-07-11 14:45:22 - JobName: [Test] is Run
Hello
2024-07-11 14:45:22 - JobName: [Test] is Done
com.amb.config.automatic.Test@5964d9e9
2024-07-11 14:45:32 - JobName: [Test] is Run
Hello
2024-07-11 14:45:32 - JobName: [Test] is Done
com.amb.config.automatic.Test@38c31fd1

Giải thích

Lớp Runner: Đây là lớp trừu tượng để thực thi các công việc, có thể được mở rộng bởi các lớp công việc cụ thể như Test.

Lớp Test: Là một lớp con của Runner để thực thi công việc in ra "Hello, world!".

Kết quả: Khi chạy, chúng ta lập lịch và thực thi công việc từ lớp Test, sau đó tạm dừng, tiếp tục và dừng lại công việc dựa trên các hành động được xác định. Mã nguồn này cho phép bạn quản lý và tự động hóa các tác vụ trong ứng dụng Java một cách linh hoạt và tiện lợi, thích hợp cho việc xử lý các công việc định kỳ hoặc theo thời gian nhất định. Cảm ơn mọi người đã đọc xong bài viết!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí