網(wǎng)站代碼多彩經(jīng)典模板網(wǎng)站建設(shè)
1、java自帶的Timer
Timer是java中自帶的類。
優(yōu)點(diǎn):使用簡單,缺點(diǎn)是當(dāng)添加并執(zhí)行多個任務(wù)時,前面任務(wù)的執(zhí)行用時和異常將影響到后面任務(wù)。
Timer timer = new Timer();timer.schedule(new TimerTask() {int i = 0;@Overridepublic void run() {System.out.println("循環(huán)執(zhí)行的代碼塊"+ i++);}},啟動后多長時間按第一次開始執(zhí)行,間隔執(zhí)行時間);
講解:源碼講解
2、ScheduledThreadPool-定時任務(wù)線程池
ScheduledExecutorService 也是Java自帶的類,它可以實(shí)現(xiàn)Timer具備的所有功能,并解決了 Timer類存在的問題。
優(yōu)點(diǎn):該類是JDK1.5自帶的類,使用簡單,缺點(diǎn)是該方案僅適用于單機(jī)環(huán)境。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(該線程池里的線程數(shù));scheduledThreadPool.scheduleAtFixedRate(new Runnable() { public void run() {System.out.println("循環(huán)代碼塊");}},初始延遲,遲期, 時間單位);
參數(shù):1、任務(wù)主體(循環(huán)代碼塊)
2、首次執(zhí)行的延時時間
3、任務(wù)執(zhí)行間隔
4、間隔時間單位
講解:源碼講解
3、Spring Task
Spring系列框架中Spring Framework自帶的定時任務(wù),可以實(shí)現(xiàn)某些特定需求,比如每周一執(zhí)行某任務(wù)。
1、開啟定時任務(wù)在SpringBoot的啟動類上聲明 @EnableScheduling
@SpringBootApplication
@EnableScheduling //開啟定時任務(wù)
public class SystemApplication { // -- --
}
2、添加定時任務(wù);只需使用@Scheduled注解標(biāo)注即可,如果有多個定時任務(wù),可以創(chuàng)建多個@Scheduled標(biāo)注的方法。Spring Boot 啟動后會自動加載并執(zhí)行定時任務(wù),無需手動操作。
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component // 把此類托管給 Spring
public class TaskUtils { // 添加定時任務(wù) @Scheduled(cron = "30 00 10 0 0 5") // cron表達(dá)式:每周一 10:00:30 執(zhí)行 public void doTask(){ System.out.println("我是定時任務(wù)~"); }
}
4、分布式定時任務(wù)
分布式環(huán)境可以使用 Redis 來實(shí)現(xiàn)定時任務(wù)。
使用 Redis 實(shí)現(xiàn)延遲任務(wù)的方法大體可分為兩類:通過 ZSet 的方式和鍵空間通知的方式。
ZSet 實(shí)現(xiàn)方式
通過 ZSet 實(shí)現(xiàn)定時任務(wù)的思路是,將定時任務(wù)存放到 ZSet 集合中,并且將過期時間存儲到 ZSet 的 Score 字段中,然后通過一個無線循環(huán)來判斷當(dāng)前時間內(nèi)是否有需要執(zhí)行的定時任務(wù),如果有則進(jìn)行執(zhí)行。
import redis.clients.jedis.Jedis;
import utils.JedisUtils;
import java.time.Instant;
import java.util.Set;
public class DelayQueueExample { private static final String _KEY = "DelayQueueExample"; public static void main(String[] args) throws InterruptedException { Jedis jedis = JedisUtils.getJedis(); // 30s 后執(zhí)行 long delayTime = Instant.now().plusSeconds(30).getEpochSecond(); jedis.zadd(_KEY, delayTime, "order_1"); // 繼續(xù)添加測試數(shù)據(jù) jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_2"); jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_3"); jedis.zadd(_KEY, Instant.now().plusSeconds(7).getEpochSecond(), "order_4"); jedis.zadd(_KEY, Instant.now().plusSeconds(10).getEpochSecond(), "order_5"); // 開啟定時任務(wù)隊(duì)列 doDelayQueue(jedis); } /** * 定時任務(wù)隊(duì)列消費(fèi) * @param jedis Redis 客戶端 */ public static void doDelayQueue(Jedis jedis) throws InterruptedException { while (true) { // 當(dāng)前時間 Instant nowInstant = Instant.now(); long lastSecond = nowInstant.plusSeconds(-1).getEpochSecond(); // 上一秒時間 long nowSecond = nowInstant.getEpochSecond(); // 查詢當(dāng)前時間的所有任務(wù) Set data = jedis.zrangeByScore(_KEY, lastSecond, nowSecond); for (String item : data) { // 消費(fèi)任務(wù) System.out.println("消費(fèi):" + item); } // 刪除已經(jīng)執(zhí)行的任務(wù) jedis.zremrangeByScore(_KEY, lastSecond, nowSecond); Thread.sleep(1000); // 每秒查詢一次 } }
}
鍵空間通知
可以通過 Redis 的鍵空間通知來實(shí)現(xiàn)定時任務(wù),它的實(shí)現(xiàn)思路是給所有的定時任務(wù)設(shè)置一個過期時間,等到了過期之后,我們通過訂閱過期消息就能感知到定時任務(wù)需要被執(zhí)行了,此時我們執(zhí)行定時任務(wù)即可。
默認(rèn)情況下 Redis 是不開啟鍵空間通知的,需要我們通過 config set notify-keyspace-events Ex 的命令手動開啟。
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import utils.JedisUtils;
public class TaskExample { public static final String _TOPIC = "__keyevent@0__:expired"; // 訂閱頻道名稱 public static void main(String[] args) { Jedis jedis = JedisUtils.getJedis(); // 執(zhí)行定時任務(wù) doTask(jedis); } /** * 訂閱過期消息,執(zhí)行定時任務(wù) * @param jedis Redis 客戶端 */ public static void doTask(Jedis jedis) { // 訂閱過期消息 jedis.psubscribe(new JedisPubSub() { @Override public void onPMessage(String pattern, String channel, String message) { // 接收到消息,執(zhí)行定時任務(wù) System.out.println("收到消息:" + message); } }, _TOPIC); }
}
SpringBoot中使用Redis實(shí)現(xiàn)分布式鎖
5、springboot整合xxl-job實(shí)現(xiàn)定時任務(wù)
注:后續(xù)繼續(xù)補(bǔ)充