Добавить Автора
Отказ от ответственности: эта статья изначально была создана компанией 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.
Выходите на остановке, увидимся на следующей остановке.