Java | Справляйтесь с задачами синхронизации за одну минуту | 4 - Многопоточный таймер

Добавить Автора

Отказ от ответственности: эта статья изначально была создана компанией Mars соус, а часть контента взята из Интернета.Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь со мной.

Перепечатка: Добро пожаловать на перепечатку, пожалуйста, свяжитесь со мной перед перепечаткой!

предисловие

Таймер, поставляемый с JDK, не может обеспечить многозадачный параллелизм, так что же нам делать с параллелизмом многозадачного времени? В этой главе будет изучен марсианский соус.

Что может придумать соус Mars, так это такие ключевые слова, как многопоточность и пул потоков.

ЗапланированныйExecutorService

ScheduledExecutorService — это интерфейсный класс, который наследует ExecutorService. ExecutorServiceMars соус помнит в Java | Одна минута, чтобы освоить асинхронное программирование | 3 — Асинхронный поток — Самородки (juejin.cn) упомянули, что при использовании многопоточности для достижения асинхронности создание пула потоков используйте Created by Executors, создайте здесь пул потоков типа задачи, мы можем использовать:

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

Переписывая предыдущий пример

Когда мы использовали Timer раньше, мы столкнулись с блокировкой. На этот раз мы используем для этого пул потоков задач. Измените пример в предыдущей статье:

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);
    }
}
复制代码

После перезаписи запустите его, и результат будет таким:

Что ж, очень аккуратно, обе задачи а и б выполняются независимо, что отлично решает проблему блокировок, вызванных общими очередями.

вот проблема

Что, если задание Марса-тян выполнять раз в месяц или задание на день рождения раз в год?

Хотя функция расписания в ScheduledExecutorService поддерживает периодические единицы до дней, если это недельная, месячная или годовая задача, мы должны сами рассчитать время выполнения следующей задачи, что все еще немного ошибочно. также способы: просто поддержите выражения cron. Но метод, предоставляемый ScheduledExecutorService, не поддерживает выражения cron. Ниже приводится введение выражения cron

cron-выражение

Выражение cron представляет собой строку со значением времени, строка начинается с 5.Разделены 6 пробелами, разделены на 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字符时,避免指定列表或者范围,否则,会导致逻辑问题。 - В поле даты буква L указывает на последний день месяца. В поле дня недели L представляет последний день недели, то есть воскресенье ( SUN ).
  • Если перед L есть определенный контент , например, 6L в поле недели означает последнюю субботу этого месяца. | | W |Действительные дни недели, кроме выходных, событие срабатывает в ближайший допустимый день недели к указанной дате. Символ W не будет пересекать текущий месяц при поиске ближайшего рабочего дня, а символ LW используется для обозначения последнего рабочего дня указанного месяца. | В поле даты 5W , если 5-е число — суббота, то сработает ближайший рабочий день, пятница, то есть 4-е. Если 5 число выпадает на воскресенье, то сработает в ближайший рабочий день, понедельник, то есть 6 число, если 5 число выпадает на день с понедельника по пятницу, сработает на 5 число. || # |Определить день недели каждого месяца, только поле недели поддерживает этот символ. | В поле недели 4#2 означает второй четверг определенного месяца.

Какие запланированные задачи поддерживают выражения cron?

Операционная система Linux поддерживает выражения cron, а Java поддерживает выражения cron с инфраструктурой Spring.

Выходите на остановке, увидимся на следующей остановке.

Supongo que te gusta

Origin juejin.im/post/7229374487174889509
Recomendado
Clasificación