首页 > 其他分享 >扩展 Cron4j 实现秒级定时任务

扩展 Cron4j 实现秒级定时任务

时间:2025-01-06 16:55:08浏览次数:7  
标签:quot pattern parser value values 秒级 Cron4j new 定时

Cron4j 是一个轻量级的 Java 定时任务调度库,默认情况下不支持秒级别的定时任务。如果需要扩展秒级别的定时任务,可以通过修改 Cron4j 的源码来实现。本文将详细介绍如何修改 Cron4j 的源码以支持秒级别的定时任务。

环境准备

首先,从 Cron4j 的 GitHub 仓库 下载源码,并导入到你的 IDE 中。pom地址如下:

<dependency>
    <groupId>it.sauronsoftware.cron4j</groupId>
    <artifactId>cron4j</artifactId>
    <version>2.2.5</version>
</dependency>

修改 SchedulingPattern 类

SchedulingPattern 类负责解析和匹配调度表达式。我们需要修改它以支持秒级别的调度。

添加秒字段:在 SchedulingPattern 类中添加对秒字段的支持。

/*
 * cron4j - A pure Java cron-like scheduler
 * 
 * Copyright (C) 2007-2010 Carlo Pelliccia (www.sauronsoftware.it)
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version
 * 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License 2.1 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License version 2.1 along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */
package it.sauronsoftware.cron4j;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.TimeZone;

/**
 * <p>
 * A UNIX crontab-like pattern is a string split in five space separated parts.
 * Each part is intented as:
 * </p>
 * <ol>
 * <li><strong>Minutes sub-pattern</strong>. During which minutes of the hour
 * should the task been launched? The values range is from 0 to 59.</li>
 * <li><strong>Hours sub-pattern</strong>. During which hours of the day should
 * the task been launched? The values range is from 0 to 23.</li>
 * <li><strong>Days of month sub-pattern</strong>. During which days of the
 * month should the task been launched? The values range is from 1 to 31. The
 * special value L can be used to recognize the last day of month.</li>
 * <li><strong>Months sub-pattern</strong>. During which months of the year
 * should the task been launched? The values range is from 1 (January) to 12
 * (December), otherwise this sub-pattern allows the aliases &quot;jan&quot;,
 * &quot;feb&quot;, &quot;mar&quot;, &quot;apr&quot;, &quot;may&quot;,
 * &quot;jun&quot;, &quot;jul&quot;, &quot;aug&quot;, &quot;sep&quot;,
 * &quot;oct&quot;, &quot;nov&quot; and &quot;dec&quot;.</li>
 * <li><strong>Days of week sub-pattern</strong>. During which days of the week
 * should the task been launched? The values range is from 0 (Sunday) to 6
 * (Saturday), otherwise this sub-pattern allows the aliases &quot;sun&quot;,
 * &quot;mon&quot;, &quot;tue&quot;, &quot;wed&quot;, &quot;thu&quot;,
 * &quot;fri&quot; and &quot;sat&quot;.</li>
 * </ol>
 * <p>
 * The star wildcard character is also admitted, indicating &quot;every minute
 * of the hour&quot;, &quot;every hour of the day&quot;, &quot;every day of the
 * month&quot;, &quot;every month of the year&quot; and &quot;every day of the
 * week&quot;, according to the sub-pattern in which it is used.
 * </p>
 * <p>
 * Once the scheduler is started, a task will be launched when the five parts in
 * its scheduling pattern will be true at the same time.
 * </p>
 * <p>
 * Some examples:
 * </p>
 * <p>
 * <strong>5 * * * *</strong><br />
 * This pattern causes a task to be launched once every hour, at the begin of
 * the fifth minute (00:05, 01:05, 02:05 etc.).
 * </p>
 * <p>
 * <strong>* * * * *</strong><br />
 * This pattern causes a task to be launched every minute.
 * </p>
 * <p>
 * <strong>* 12 * * Mon</strong><br />
 * This pattern causes a task to be launched every minute during the 12th hour
 * of Monday.
 * </p>
 * <p>
 * <strong>* 12 16 * Mon</strong><br />
 * This pattern causes a task to be launched every minute during the 12th hour
 * of Monday, 16th, but only if the day is the 16th of the month.
 * </p>
 * <p>
 * Every sub-pattern can contain two or more comma separated values.
 * </p>
 * <p>
 * <strong>59 11 * * 1,2,3,4,5</strong><br />
 * This pattern causes a task to be launched at 11:59AM on Monday, Tuesday,
 * Wednesday, Thursday and Friday.
 * </p>
 * <p>
 * Values intervals are admitted and defined using the minus character.
 * </p>
 * <p>
 * <strong>59 11 * * 1-5</strong><br />
 * This pattern is equivalent to the previous one.
 * </p>
 * <p>
 * The slash character can be used to identify step values within a range. It
 * can be used both in the form <em>*&#47;c</em> and <em>a-b/c</em>. The
 * subpattern is matched every <em>c</em> values of the range
 * <em>0,maxvalue</em> or <em>a-b</em>.
 * </p>
 * <p>
 * <strong>*&#47;5 * * * *</strong><br />
 * This pattern causes a task to be launched every 5 minutes (0:00, 0:05, 0:10,
 * 0:15 and so on).
 * </p>
 * <p>
 * <strong>3-18&#47;5 * * * *</strong><br />
 * This pattern causes a task to be launched every 5 minutes starting from the
 * third minute of the hour, up to the 18th (0:03, 0:08, 0:13, 0:18, 1:03, 1:08
 * and so on).
 * </p>
 * <p>
 * <strong>*&#47;15 9-17 * * *</strong><br />
 * This pattern causes a task to be launched every 15 minutes between the 9th
 * and 17th hour of the day (9:00, 9:15, 9:30, 9:45 and so on... note that the
 * last execution will be at 17:45).
 * </p>
 * <p>
 * All the fresh described syntax rules can be used together.
 * </p>
 * <p>
 * <strong>* 12 10-16&#47;2 * *</strong><br />
 * This pattern causes a task to be launched every minute during the 12th hour
 * of the day, but only if the day is the 10th, the 12th, the 14th or the 16th
 * of the month.
 * </p>
 * <p>
 * <strong>* 12 1-15,17,20-25 * *</strong><br />
 * This pattern causes a task to be launched every minute during the 12th hour
 * of the day, but the day of the month must be between the 1st and the 15th,
 * the 20th and the 25, or at least it must be the 17th.
 * </p>
 * <p>
 * Finally cron4j lets you combine more scheduling patterns into one, with the
 * pipe character:
 * </p>
 * <p>
 * <strong>0 5 * * *|8 10 * * *|22 17 * * *</strong><br />
 * This pattern causes a task to be launched every day at 05:00, 10:08 and
 * 17:22.
 * </p>
 * 
 * @author Carlo Pelliccia
 * @since 2.0
 */
public class SchedulingPattern {

	/**
	 * The parser for the second values.
	 */
	private static final ValueParser SECONDS_VALUE_PARSER = new SecondsValueParser();
	
	/**
	 * The parser for the minute values.
	 */
	private static final ValueParser MINUTE_VALUE_PARSER = new MinuteValueParser();

	/**
	 * The parser for the hour values.
	 */
	private static final ValueParser HOUR_VALUE_PARSER = new HourValueParser();

	/**
	 * The parser for the day of month values.
	 */
	private static final ValueParser DAY_OF_MONTH_VALUE_PARSER = new DayOfMonthValueParser();

	/**
	 * The parser for the month values.
	 */
	private static final ValueParser MONTH_VALUE_PARSER = new MonthValueParser();

	/**
	 * The parser for the day of week values.
	 */
	private static final ValueParser DAY_OF_WEEK_VALUE_PARSER = new DayOfWeekValueParser();

	/**
	 * Validates a string as a scheduling pattern.
	 * 
	 * @param schedulingPattern
	 *            The pattern to validate.
	 * @return true if the given string represents a valid scheduling pattern;
	 *         false otherwise.
	 */
	public static boolean validate(String schedulingPattern) {
		try {
			new SchedulingPattern(schedulingPattern);
		} catch (InvalidPatternException e) {
			return false;
		}
		return true;
	}

	/**
	 * The pattern as a string.
	 */
	private String asString;

	/**
	 * The ValueMatcher list for the "minute" field.
	 */
	protected ArrayList secondsMatchers = new ArrayList();
	
	/**
	 * The ValueMatcher list for the "minute" field.
	 */
	protected ArrayList minuteMatchers = new ArrayList();

	/**
	 * The ValueMatcher list for the "hour" field.
	 */
	protected ArrayList hourMatchers = new ArrayList();

	/**
	 * The ValueMatcher list for the "day of month" field.
	 */
	protected ArrayList dayOfMonthMatchers = new ArrayList();

	/**
	 * The ValueMatcher list for the "month" field.
	 */
	protected ArrayList monthMatchers = new ArrayList();

	/**
	 * The ValueMatcher list for the "day of week" field.
	 */
	protected ArrayList dayOfWeekMatchers = new ArrayList();

	/**
	 * How many matcher groups in this pattern?
	 */
	protected int matcherSize = 0;

	/**
	 * Builds a SchedulingPattern parsing it from a string.
	 * 
	 * @param pattern
	 *            The pattern as a crontab-like string.
	 * @throws InvalidPatternException
	 *             If the supplied string is not a valid pattern.
	 */
	public SchedulingPattern(String pattern) throws InvalidPatternException {
		this.asString = pattern;
		StringTokenizer st1 = new StringTokenizer(pattern, "|");
		if (st1.countTokens() < 1) {
			throw new InvalidPatternException("invalid pattern: \"" + pattern + "\"");
		}
		while (st1.hasMoreTokens()) {
			String localPattern = st1.nextToken();
			StringTokenizer st2 = new StringTokenizer(localPattern, " \t");
			if (st2.countTokens() != 6) {
				throw new InvalidPatternException("invalid pattern: \"" + localPattern + "\"");
			}
			
			try {
				secondsMatchers.add(buildValueMatcher(st2.nextToken(), SECONDS_VALUE_PARSER));
			} catch (Exception e) {
				throw new InvalidPatternException("invalid pattern \""
						+ localPattern + "\". Error parsing minutes field: "
						+ e.getMessage() + ".");
			}
			
			try {
				minuteMatchers.add(buildValueMatcher(st2.nextToken(), MINUTE_VALUE_PARSER));
			} catch (Exception e) {
				throw new InvalidPatternException("invalid pattern \""
						+ localPattern + "\". Error parsing minutes field: "
						+ e.getMessage() + ".");
			}
			try {
				hourMatchers.add(buildValueMatcher(st2.nextToken(), HOUR_VALUE_PARSER));
			} catch (Exception e) {
				throw new InvalidPatternException("invalid pattern \""
						+ localPattern + "\". Error parsing hours field: "
						+ e.getMessage() + ".");
			}
			try {
				dayOfMonthMatchers.add(buildValueMatcher(st2.nextToken(), DAY_OF_MONTH_VALUE_PARSER));
			} catch (Exception e) {
				throw new InvalidPatternException("invalid pattern \""
						+ localPattern
						+ "\". Error parsing days of month field: "
						+ e.getMessage() + ".");
			}
			try {
				monthMatchers.add(buildValueMatcher(st2.nextToken(), MONTH_VALUE_PARSER));
			} catch (Exception e) {
				throw new InvalidPatternException("invalid pattern \""
						+ localPattern + "\". Error parsing months field: "
						+ e.getMessage() + ".");
			}
			try {
				dayOfWeekMatchers.add(buildValueMatcher(st2.nextToken(), DAY_OF_WEEK_VALUE_PARSER));
			} catch (Exception e) {
				throw new InvalidPatternException("invalid pattern \""
						+ localPattern
						+ "\". Error parsing days of week field: "
						+ e.getMessage() + ".");
			}
			matcherSize++;
		}
	}

	/**
	 * A ValueMatcher utility builder.
	 * 
	 * @param str
	 *            The pattern part for the ValueMatcher creation.
	 * @param parser
	 *            The parser used to parse the values.
	 * @return The requested ValueMatcher.
	 * @throws Exception
	 *             If the supplied pattern part is not valid.
	 */
	private ValueMatcher buildValueMatcher(String str, ValueParser parser)
			throws Exception {
		if (str.length() == 1 && str.equals("*")) {
			return new AlwaysTrueValueMatcher();
		}
		ArrayList values = new ArrayList();
		StringTokenizer st = new StringTokenizer(str, ",");
		while (st.hasMoreTokens()) {
			String element = st.nextToken();
			ArrayList local;
			try {
				local = parseListElement(element, parser);
			} catch (Exception e) {
				throw new Exception("invalid field \"" + str
						+ "\", invalid element \"" + element + "\", "
						+ e.getMessage());
			}
			for (Iterator i = local.iterator(); i.hasNext();) {
				Object value = i.next();
				if (!values.contains(value)) {
					values.add(value);
				}
			}
		}
		if (values.size() == 0) {
			throw new Exception("invalid field \"" + str + "\"");
		}
		if (parser == DAY_OF_MONTH_VALUE_PARSER) {
			return new DayOfMonthValueMatcher(values);
		} else {
			return new IntArrayValueMatcher(values);
		}
	}

	/**
	 * Parses an element of a list of values of the pattern.
	 * 
	 * @param str
	 *            The element string.
	 * @param parser
	 *            The parser used to parse the values.
	 * @return A list of integers representing the allowed values.
	 * @throws Exception
	 *             If the supplied pattern part is not valid.
	 */
	private ArrayList parseListElement(String str, ValueParser parser)
			throws Exception {
		StringTokenizer st = new StringTokenizer(str, "/");
		int size = st.countTokens();
		if (size < 1 || size > 2) {
			throw new Exception("syntax error");
		}
		ArrayList values;
		try {
			values = parseRange(st.nextToken(), parser);
		} catch (Exception e) {
			throw new Exception("invalid range, " + e.getMessage());
		}
		if (size == 2) {
			String dStr = st.nextToken();
			int div;
			try {
				div = Integer.parseInt(dStr);
			} catch (NumberFormatException e) {
				throw new Exception("invalid divisor \"" + dStr + "\"");
			}
			if (div < 1) {
				throw new Exception("non positive divisor \"" + div + "\"");
			}
			ArrayList values2 = new ArrayList();
			for (int i = 0; i < values.size(); i += div) {
				values2.add(values.get(i));
			}
			return values2;
		} else {
			return values;
		}
	}

	/**
	 * Parses a range of values.
	 * 
	 * @param str
	 *            The range string.
	 * @param parser
	 *            The parser used to parse the values.
	 * @return A list of integers representing the allowed values.
	 * @throws Exception
	 *             If the supplied pattern part is not valid.
	 */
	private ArrayList parseRange(String str, ValueParser parser)
			throws Exception {
		if (str.equals("*")) {
			int min = parser.getMinValue();
			int max = parser.getMaxValue();
			ArrayList values = new ArrayList();
			for (int i = min; i <= max; i++) {
				values.add(new Integer(i));
			}
			return values;
		}
		StringTokenizer st = new StringTokenizer(str, "-");
		int size = st.countTokens();
		if (size < 1 || size > 2) {
			throw new Exception("syntax error");
		}
		String v1Str = st.nextToken();
		int v1;
		try {
			v1 = parser.parse(v1Str);
		} catch (Exception e) {
			throw new Exception("invalid value \"" + v1Str + "\", "
					+ e.getMessage());
		}
		if (size == 1) {
			ArrayList values = new ArrayList();
			values.add(new Integer(v1));
			return values;
		} else {
			String v2Str = st.nextToken();
			int v2;
			try {
				v2 = parser.parse(v2Str);
			} catch (Exception e) {
				throw new Exception("invalid value \"" + v2Str + "\", "
						+ e.getMessage());
			}
			ArrayList values = new ArrayList();
			if (v1 < v2) {
				for (int i = v1; i <= v2; i++) {
					values.add(new Integer(i));
				}
			} else if (v1 > v2) {
				int min = parser.getMinValue();
				int max = parser.getMaxValue();
				for (int i = v1; i <= max; i++) {
					values.add(new Integer(i));
				}
				for (int i = min; i <= v2; i++) {
					values.add(new Integer(i));
				}
			} else {
				// v1 == v2
				values.add(new Integer(v1));
			}
			return values;
		}
	}

	/**
	 * This methods returns true if the given timestamp (expressed as a UNIX-era
	 * millis value) matches the pattern, according to the given time zone.
	 * 
	 * @param timezone
	 *            A time zone.
	 * @param millis
	 *            The timestamp, as a UNIX-era millis value.
	 * @return true if the given timestamp matches the pattern.
	 */
	public boolean match(TimeZone timezone, long millis) {
		GregorianCalendar gc = new GregorianCalendar();
		gc.setTimeInMillis(millis);
		gc.setTimeZone(timezone);
		int seconds = gc.get(Calendar.SECOND);
		int minute = gc.get(Calendar.MINUTE);
		int hour = gc.get(Calendar.HOUR_OF_DAY);
		int dayOfMonth = gc.get(Calendar.DAY_OF_MONTH);
		int month = gc.get(Calendar.MONTH) + 1;
		int dayOfWeek = gc.get(Calendar.DAY_OF_WEEK) - 1;
		int year = gc.get(Calendar.YEAR);
		for (int i = 0; i < matcherSize; i++) {
			ValueMatcher secondsMatcher = (ValueMatcher) secondsMatchers.get(i);
			ValueMatcher minuteMatcher = (ValueMatcher) minuteMatchers.get(i);
			ValueMatcher hourMatcher = (ValueMatcher) hourMatchers.get(i);
			ValueMatcher dayOfMonthMatcher = (ValueMatcher) dayOfMonthMatchers.get(i);
			ValueMatcher monthMatcher = (ValueMatcher) monthMatchers.get(i);
			ValueMatcher dayOfWeekMatcher = (ValueMatcher) dayOfWeekMatchers.get(i);
			boolean eval = secondsMatcher.match(seconds)
					&&minuteMatcher.match(minute)
					&& hourMatcher.match(hour)
					&& ((dayOfMonthMatcher instanceof DayOfMonthValueMatcher) ? ((DayOfMonthValueMatcher) dayOfMonthMatcher)
							.match(dayOfMonth, month, gc.isLeapYear(year))
							: dayOfMonthMatcher.match(dayOfMonth))
					&& monthMatcher.match(month)
					&& dayOfWeekMatcher.match(dayOfWeek);
			if (eval) {
				return true;
			}
		}
		return false;
	}

	/**
	 * This methods returns true if the given timestamp (expressed as a UNIX-era
	 * millis value) matches the pattern, according to the system default time
	 * zone.
	 * 
	 * @param millis
	 *            The timestamp, as a UNIX-era millis value.
	 * @return true if the given timestamp matches the pattern.
	 */
	public boolean match(long millis) {
		return match(TimeZone.getDefault(), millis);
	}

	/**
	 * Returns the pattern as a string.
	 * 
	 * @return The pattern as a string.
	 */
	public String toString() {
		return asString;
	}

	/**
	 * This utility method changes an alias to an int value.
	 * 
	 * @param value
	 *            The value.
	 * @param aliases
	 *            The aliases list.
	 * @param offset
	 *            The offset appplied to the aliases list indices.
	 * @return The parsed value.
	 * @throws Exception
	 *             If the expressed values doesn't match any alias.
	 */
	private static int parseAlias(String value, String[] aliases, int offset)
			throws Exception {
		for (int i = 0; i < aliases.length; i++) {
			if (aliases[i].equalsIgnoreCase(value)) {
				return offset + i;
			}
		}
		throw new Exception("invalid alias \"" + value + "\"");
	}

	/**
	 * Definition for a value parser.
	 */
	private static interface ValueParser {

		/**
		 * Attempts to parse a value.
		 * 
		 * @param value
		 *            The value.
		 * @return The parsed value.
		 * @throws Exception
		 *             If the value can't be parsed.
		 */
		public int parse(String value) throws Exception;

		/**
		 * Returns the minimum value accepred by the parser.
		 * 
		 * @return The minimum value accepred by the parser.
		 */
		public int getMinValue();

		/**
		 * Returns the maximum value accepred by the parser.
		 * 
		 * @return The maximum value accepred by the parser.
		 */
		public int getMaxValue();

	}

	/**
	 * A simple value parser.
	 */
	private static class SimpleValueParser implements ValueParser {

		/**
		 * The minimum allowed value.
		 */
		protected int minValue;

		/**
		 * The maximum allowed value.
		 */
		protected int maxValue;

		/**
		 * Builds the value parser.
		 * 
		 * @param minValue
		 *            The minimum allowed value.
		 * @param maxValue
		 *            The maximum allowed value.
		 */
		public SimpleValueParser(int minValue, int maxValue) {
			this.minValue = minValue;
			this.maxValue = maxValue;
		}

		public int parse(String value) throws Exception {
			int i;
			try {
				i = Integer.parseInt(value);
			} catch (NumberFormatException e) {
				throw new Exception("invalid integer value");
			}
			if (i < minValue || i > maxValue) {
				throw new Exception("value out of range");
			}
			return i;
		}

		public int getMinValue() {
			return minValue;
		}

		public int getMaxValue() {
			return maxValue;
		}

	}

	/**
	 * The minutes value parser.
	 */
	private static class SecondsValueParser extends SimpleValueParser {

		/**
		 * Builds the value parser.
		 */
		public SecondsValueParser() {
			super(0, 59);
		}

	}
	
	/**
	 * The minutes value parser.
	 */
	private static class MinuteValueParser extends SimpleValueParser {

		/**
		 * Builds the value parser.
		 */
		public MinuteValueParser() {
			super(0, 59);
		}

	}

	/**
	 * The hours value parser.
	 */
	private static class HourValueParser extends SimpleValueParser {

		/**
		 * Builds the value parser.
		 */
		public HourValueParser() {
			super(0, 23);
		}

	}

	/**
	 * The days of month value parser.
	 */
	private static class DayOfMonthValueParser extends SimpleValueParser {

		/**
		 * Builds the value parser.
		 */
		public DayOfMonthValueParser() {
			super(1, 31);
		}

		/**
		 * Added to support last-day-of-month.
		 * 
		 * @param value
		 *            The value to be parsed
		 * @return the integer day of the month or 32 for last day of the month
		 * @throws Exception
		 *             if the input value is invalid
		 */
		public int parse(String value) throws Exception {
			if (value.equalsIgnoreCase("L")) {
				return 32;
			} else {
				return super.parse(value);
			}
		}

	}

	/**
	 * The value parser for the months field.
	 */
	private static class MonthValueParser extends SimpleValueParser {

		/**
		 * Months aliases.
		 */
		private static String[] ALIASES = { "jan", "feb", "mar", "apr", "may",
				"jun", "jul", "aug", "sep", "oct", "nov", "dec" };

		/**
		 * Builds the months value parser.
		 */
		public MonthValueParser() {
			super(1, 12);
		}

		public int parse(String value) throws Exception {
			try {
				// try as a simple value
				return super.parse(value);
			} catch (Exception e) {
				// try as an alias
				return parseAlias(value, ALIASES, 1);
			}
		}

	}

	/**
	 * The value parser for the months field.
	 */
	private static class DayOfWeekValueParser extends SimpleValueParser {

		/**
		 * Days of week aliases.
		 */
		private static String[] ALIASES = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };

		/**
		 * Builds the months value parser.
		 */
		public DayOfWeekValueParser() {
			super(0, 7);
		}

		public int parse(String value) throws Exception {
			try {
				// try as a simple value
				return super.parse(value) % 7;
			} catch (Exception e) {
				// try as an alias
				return parseAlias(value, ALIASES, 0);
			}
		}

	}

}

使用方法:

首先,将上述修改后的类替换 cron4j 中的原类。
然后,传入的 cron 表达式要采用新的格式,包含秒级信息,例如 "0 0 0 * * *" 表示在每天的 0 点 0 分 0 秒执行任务,或者 "0-30 * * * * *" 表示每分钟的 0 到 30 秒都执行任务。
请注意,上述代码仅为示例,实际修改 cron4j 的源码可能会涉及更多复杂的细节,例如异常处理、并发问题、cron 表达式更复杂的匹配逻辑等,需要根据 cron4j 的实际源码进行更深入的修改和完善。此外,修改源码可能会影响其兼容性和稳定性,需要进行充分的测试。

标签:quot,pattern,parser,value,values,秒级,Cron4j,new,定时
From: https://www.cnblogs.com/chqxyzhu/p/18655677

相关文章

  • 定时任务与异步任务:django-apscheduler 与 django-Q的区别
    django-apscheduler和django-Q是两个用于调度任务和异步任务处理的Django扩展库,但它们的功能和设计目标有所不同。以下是两者的主要区别:1.django-apschedulerdjango-apscheduler是Django框架下的一个定时任务调度工具,它基于Python的APScheduler实现。它主要......
  • C++ 实现定时器
    冬天的午后,寒意略显温柔,不像晨时那样刺骨,也不像入夜之时的冰冷。阳光倾斜落在阳台上。想必它是耀眼的,照在屋外树梢上仅剩的几片叶子上,闪闪发光,有些晃眼。学习自:零声教育的视频1.什么是定时器定时器是一种用于在未来某个时间点执行某个任务的机制。在操作系统中,定时器是一......
  • 注册托管服务+timer实现简单定时任务
    1.创建服务类publicclassTimerService:IHostedService,IDisposable{///<summary>///定义定时器///</summary>privatestaticSystem.Threading.Timer_timer;privatestaticint_count=0;///<summary>......
  • WiFi+4G摄像头拍照图传模块(夜视2K高清1080P)-定时拍照http post上传到服务器,然后低
    <p><iframename="ifd"src="https://mnifdv.cn/resource/cnblogs/product/audioCamera.html"frameborder="0"scrolling="auto"width="100%"height="1500"></iframe></p> 提示!1,......
  • 第6章 定时、计数技术
    8253的主要特性可编程定时器/计数器有3个16位计数通道,每个计数器分成2个8位计数器。计数频率为0~2.6MHZ。(112.6微秒)每个计数通道可按二进制或BCD方式计数。6种工作方式,可由程序设置和改变。可由软件或硬件控制开始计数或停止计数。8253的内部结构数据总线缓冲器......
  • 时间规则 定时器
    */5****?#每隔5秒执行一次0*/1***?#每隔1分钟执行一次0021*?*#每月1日的凌晨2点执行一次01510?*#MON-FRI周一到周五每天上午10:15执行01510?6L#2002-20062002年至2006年的每个月的最后一个星期五上午10:15执行0......
  • SpringBoot 整合 Quartz 定时任务框架
    本文没有聊到 Java 其他的实现定时任务的方法啥的~,只是对使用Quartz做了一个小实践一、简单聊一聊QuartzQuartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz其实就是通过一个调度线程不断的扫描数据库......
  • MongoDB或TOMCAT定时切割日志文件的脚本.250103
    MongoDB用过一段时间后,日志较大,需要定时进行日志切割。一、切割bash:splitlogmongo.sh#!/bin/bashlog_dir="/home/mongodb/logs"file_name="/home/mongodb/logs/mongodb.log"if[!-d$log_dir];thenmkdir-p$log_dirfiif[!-f$file_name];thentouch$file_name......
  • 14. 定时器控件
    一、定时器控件  在PySide6中,如果需要周期性地执行某项操作,就可以使用QTimer类实现。QTimer类表示计时器,它可以定期发射timeout信号,执行与信号连接的槽函数,实现自动完成某些功能。时间间隔的长度可以在start()方法中指定,以毫秒为单位。如果需要停止定时器,则需要使用s......
  • opencv中findCirclesGrid在标定时使用,blobDetector 参数怎么定义?
    在OpenCV中,findCirclesGrid是一个用于检测图像中的圆形格点(通常用于相机标定或校正的检测目标)的函数。它可以用于查找在特定模式下排列的圆形图案,如棋盘格或圆形网格。该函数是相机标定和立体视觉的重要工具。函数原型boolcv::findCirclesGrid(InputArrayimage,S......