Java | Maîtriser les tâches de chronométrage en une minute | 4 - Minuteur multithread

Auteur : Mars Sauce

Avis de non-responsabilité : cet article a été créé à l'origine par Mars sauce, et une partie du contenu provient d'Internet. Si vous avez des questions, n'hésitez pas à me contacter.

Réimpression : bienvenue à réimprimer, veuillez me contacter avant de réimprimer !

avant-propos

Le minuteur fourni avec le JDK ne peut pas atteindre la simultanéité multitâche, alors comment gérons-nous la simultanéité de la synchronisation multitâche ? Dans ce chapitre, la sauce Mars sera étudiée.

Ce à quoi la sauce Mars peut penser, ce sont des mots-clés tels que le multi-threading et le pool de threads.

ScheduledExecutorService

ScheduledExecutorService est une classe d'interface qui hérite d'ExecutorService. La sauce ExecutorServiceMars se souvient en Java | Une minute pour maîtriser la programmation asynchrone | 3 - Thread asynchrone - Nuggets (juejin.cn) a mentionné que lors de l'utilisation du multi-threading pour obtenir l'asynchronisme, la création d'un pool de threads consiste à utilisez Créé par les exécuteurs, créez ici un pool de threads de type tâche, nous pouvons utiliser :

// mars酱
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool();
复制代码

Réécriture de l'exemple précédent

Lorsque nous utilisions Timer auparavant, nous rencontrions un blocage. Cette fois, nous utilisons le pool de threads de tâches pour le faire. Modifiez l'exemple de l'article précédent :

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author mars酱
 */
public class MarsTimer {
    public static void main(String[] args) {
//        java.util.Timer timer = new Timer();
//        timer.schedule(new TimerTask() {
//            @Override
//            public void run() {
//                System.out.println("当前时间:" + new Date());
//            }
//        }, 1000, 5000);

        // 1. 创建第一个任务,打印时间后延迟5秒
        TimerTask tta = new TimerTask() {
            @SneakyThrows
            @Override
            public void run() {
                System.out.println(">> 这是a任务:当前时间:" + new Date());
                Thread.sleep(5000);
            }
        };

        // 2. 创建第二个任务,直接打印毫秒数
        TimerTask ttb = new TimerTask() {
            @Override
            public void run() {
                System.out.println("<< 这是b任务:当前毫秒:" + System.currentTimeMillis());
            }
        };

//        Timer timera = new Timer();
//        // 3. 把两个任务都加入计时器中
//        timera.schedule(tta, 1000, 5000);
//        timera.schedule(ttb, 1000, 5000);
        // 3. 创建一个核心线程为5的池
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
        // 4. 塞入第一个任务,5秒的一遍
        scheduledExecutorService.scheduleAtFixedRate(tta, 1000, 5000, TimeUnit.MILLISECONDS);
        // 5. 塞入第二个任务,也是5秒一遍
        scheduledExecutorService.scheduleAtFixedRate(ttb, 1000, 5000, TimeUnit.MILLISECONDS);
    }
}
复制代码

Après réécriture, exécutez-le, et le résultat est:

Eh bien, c'est très soigné. Les tâches a et b s'exécutent indépendamment, ce qui résout parfaitement le problème de blocage causé par les files d'attente partagées.

voici le problème

Que se passe-t-il si la tâche de Mars-chan est effectuée une fois par mois, ou la tâche d'anniversaire est effectuée une fois par an ?

Bien que la fonction de planification dans ScheduledExecutorService prenne en charge des unités périodiques allant jusqu'à des jours, s'il s'agit d'une tâche hebdomadaire, mensuelle ou annuelle, nous devons calculer nous-mêmes l'heure à laquelle la tâche suivante est exécutée, ce qui est encore un peu imparfait. sont également des moyens : il suffit de prendre en charge les expressions cron. Mais la méthode fournie par ScheduledExecutorService ne prend pas en charge les expressions cron. Voici l'introduction de l'expression cron

expression cron

L'expression cron est une chaîne avec une signification temporelle, la chaîne commence par 5Séparé par 6 espaces, divisé en 67个域,格式为X X X X X X X。其中X是一个域的占位符。最后一个代表年份的域非必须,可省略。单个域有多个取值时,使用半角逗号 , 隔开取值。每个域可以是确定的取值,也可以是具有逻辑意义的特殊字符。每个域最多支持一个前导零。比如:

0 10 01 ? * * 2023
复制代码

表示2023年每天凌晨1点10分执行任务

域占位符的取值

下表为cron表达式中支持的特殊字符,以及含义:

特殊字符 含义 示例
***** 所有可能的值。 在月域中, ***** 表示每个月;在星期域中, ***** 表示星期的每一天。
, 列出枚举值。 在分钟域中,5,20表示分别在5分钟和20分钟触发一次。
- 范围。 在分钟域中,5-20表示从5分钟到20分钟之间每隔一分钟触发一次。
/ 指定数值的增量。 在分钟域中,0/15表示从第0分钟开始,每15分钟。在分钟域中3/20表示从第3分钟开始,每20分钟。
? 不指定值,仅日期和星期域支持该字符。 当日期或星期域其中之一被指定了值以后,为了避免冲突,需要将另一个域的值设为 ?
L 单词Last的首字母,表示最后一天,仅日期和星期域支持该字符。说明 指定L字符时,避免指定列表或者范围,否则,会导致逻辑问题。 - Dans un champ de date, L indique le dernier jour d'un mois. Dans le champ jour de la semaine, L représente le dernier jour de la semaine, qui est dimanche ( SOLEIL ).
  • S'il y a un contenu spécifique avant L , par exemple, 6L dans le champ de la semaine signifie le dernier samedi de ce mois. | | W | Jours de semaine valides sauf les week-ends, l'événement est déclenché le jour de semaine valide le plus proche de la date spécifiée. Le caractère W ne croisera pas le mois en cours lors de la recherche du jour ouvrable effectif le plus proche, et le caractère LW est utilisé pour indiquer le dernier jour ouvrable du mois spécifié. | Dans le champ date 5W , si le 5 est un samedi, il sera déclenché le jour ouvrable le plus proche, le vendredi, c'est-à-dire le 4. Si le 5 est le dimanche, il sera déclenché le jour ouvrable le plus proche, le lundi, c'est-à-dire le 6 ; si le 5 tombe un jour du lundi au vendredi, il sera déclenché le 5. | | # | Détermine le jour de la semaine de chaque mois, seul le champ semaine prend en charge ce caractère. | Dans le champ de la semaine, 4#2 signifie le deuxième jeudi d'un certain mois.

Quelles tâches planifiées prennent en charge les expressions cron ?

Le système d'exploitation Linux prend en charge les expressions cron et Java prend en charge les expressions cron avec le framework Spring.

Descendez à la gare et rendez-vous à la prochaine gare.

Je suppose que tu aimes

Origine juejin.im/post/7229374487174889509
conseillé
Classement