日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

实现定时器

發(fā)布時(shí)間:2024/1/18 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实现定时器 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

1.定時(shí)器是什么

2.標(biāo)準(zhǔn)庫(kù)中的定時(shí)器

3.實(shí)現(xiàn)定時(shí)器


1.定時(shí)器是什么

定時(shí)器也是軟件開(kāi)發(fā)中的一個(gè)重要組件 . 類(lèi)似于一個(gè) " 鬧鐘 ". 達(dá)到一個(gè)設(shè)定的時(shí)間之后 , 就執(zhí)行某個(gè)指定好的代碼。 🍃1.定時(shí)器是一種實(shí)際開(kāi)發(fā)中非常常用的組件 . 🍃2.比如網(wǎng)絡(luò)通信中 , 如果對(duì)方 500ms 內(nèi)沒(méi)有返回?cái)?shù)據(jù) , 則斷開(kāi)連接嘗試重連 . 🍃3.比如一個(gè) Map, 希望里面的某個(gè) key 3s 之后過(guò)期 ( 自動(dòng)刪除 ). 🍃4.類(lèi)似于這樣的場(chǎng)景就需要用到定時(shí)器 .

2.標(biāo)準(zhǔn)庫(kù)中的定時(shí)器

public class TestDemo1 {public static void main(String[] args) throws InterruptedException {// java.util 里的一個(gè)組件Timer timer = new Timer();// schedule : 安排一個(gè)任務(wù)// 該任務(wù)不是立刻執(zhí)行,而是延遲多少時(shí)間后再執(zhí)行!!timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("這是一個(gè)要執(zhí)行的任務(wù)!");}},3000);// 定時(shí)器 和 sleep 不相同while(true) {System.out.println("main");Thread.sleep(1000);}} }

🍁【注意事項(xiàng)】?

🍃1.定時(shí)器的核心方法是 schedule schedule 包含兩個(gè)參數(shù),第一個(gè)參數(shù)指定即將要執(zhí)行的任務(wù),第二個(gè)參數(shù)指定多長(zhǎng)時(shí)間后執(zhí)行(單位:毫秒)。

🍃2.將定時(shí)器和 sleep 做區(qū)分,sleep 是使當(dāng)前線(xiàn)程處于阻塞狀態(tài),而 定時(shí)器 只是記錄了多長(zhǎng)時(shí)間后該執(zhí)行的任務(wù),中間的這些時(shí)間,當(dāng)前線(xiàn)程該干嘛就干嘛。

🍃3.schedule 里面的 TimerTask 其實(shí)就相當(dāng)于 Runnable,只不過(guò)是 TimerTask 實(shí)現(xiàn)了 Runnable 接口,在這里我們直接把它當(dāng)成 Runnable 就好了。

3.實(shí)現(xiàn)定時(shí)器

通過(guò)觀(guān)察標(biāo)準(zhǔn)庫(kù)中的定時(shí)器,我們大概知道要怎么做了!!

🍃1. Timer 內(nèi)部要組織很多的任務(wù);

🍃2. Timer 里的每個(gè)任務(wù)都要通過(guò)一定的方式來(lái)描述出來(lái);(自己定義一個(gè) TimerTask

🍃3. 還需要有一個(gè)線(xiàn)程,通過(guò)這個(gè)線(xiàn)程來(lái)掃描定時(shí)器內(nèi)部的任務(wù),執(zhí)行其中時(shí)間到了的任務(wù)。(Timer 內(nèi)部的線(xiàn)程)

🍁【代碼實(shí)現(xiàn)】

class MyTask implements Comparable<MyTask>{// 任務(wù)private Runnable command;// 任務(wù)開(kāi)始執(zhí)行的時(shí)間(相對(duì)時(shí)間)private long time;public MyTask(Runnable command, long after) {this.command = command;// 絕對(duì)時(shí)間戳this.time = System.currentTimeMillis() + after;}// 執(zhí)行任務(wù)的方法,直接在內(nèi)部調(diào)用 Runnable 的 run 方法即可public void run() {command.run();}public long getTime() {return time;}@Overridepublic int compareTo(MyTask o) {return (int) (this.time - o.time);} } //自己創(chuàng)建的定時(shí)器類(lèi) class MyTimer {// 用來(lái)阻塞等待的鎖對(duì)象private Object locker = new Object();// 使用優(yōu)先級(jí)阻塞隊(duì)列來(lái)保存若干個(gè)任務(wù)private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();// command : 要執(zhí)行的任務(wù)是啥// after : 任務(wù)啥時(shí)候執(zhí)行public void schedule(Runnable command, long after) {MyTask myTask = new MyTask(command, after);synchronized (locker) {queue.put(myTask);locker.notify();}}public MyTimer() {//在這里啟動(dòng)一個(gè)線(xiàn)程Thread t = new Thread(() -> {while(true) {//循環(huán)過(guò)程中,就不斷的嘗試從隊(duì)列中獲取到隊(duì)首元素//判斷隊(duì)首元素當(dāng)前的時(shí)間是否就緒,如果就緒了就執(zhí)行,不就緒,就不執(zhí)行try {synchronized (locker) {//隊(duì)列為空,也要等待if(queue.isEmpty()) {locker.wait();}//取出隊(duì)首任務(wù)MyTask myTask = queue.take();long curTime = System.currentTimeMillis();if(myTask.getTime() > curTime) {//時(shí)間還沒(méi)到,就放回去queue.put(myTask);//等待最早的任務(wù)開(kāi)始的時(shí)間和當(dāng)前時(shí)間的差值locker.wait(myTask.getTime() - curTime);} else {//時(shí)間到了,就執(zhí)行任務(wù)myTask.run();}}} catch (InterruptedException e) {e.printStackTrace();}}});t.start();} }

【分析實(shí)現(xiàn)過(guò)程中的重點(diǎn)步驟】

🍁重點(diǎn) 1:使用優(yōu)先級(jí)阻塞隊(duì)列將我們的任務(wù)組織起來(lái)!!

🍃1.雖然任務(wù)可能有很多,但是它們的執(zhí)行順序是一定的,且按照時(shí)間順序先后來(lái)執(zhí)行的,所以使用優(yōu)先級(jí)隊(duì)列。

🍃2.在多線(xiàn)程環(huán)境下,這個(gè)隊(duì)列會(huì)被多個(gè)線(xiàn)程訪(fǎng)問(wèn),第一,schedule 可能是在多線(xiàn)程中被調(diào)用,每次調(diào)用都要往隊(duì)里添加元素;第二,定時(shí)器內(nèi)部還需要有專(zhuān)門(mén)的線(xiàn)程來(lái)執(zhí)行隊(duì)列里的任務(wù)。這些操作在多線(xiàn)程里都是存在線(xiàn)程安全問(wèn)題的,所以需要使用到優(yōu)先級(jí)阻塞隊(duì)列!!

🍁重點(diǎn)2:優(yōu)先級(jí)阻塞隊(duì)列里的元素是一個(gè)引用類(lèi)型(MyTask),所以我們需要指定比較規(guī)則,既可以讓 MyTask 實(shí)現(xiàn) Comparable 接口,也可以在優(yōu)先級(jí)阻塞隊(duì)列的構(gòu)造方法中傳參,傳一個(gè)比較器 Comparator !!

🍁重點(diǎn)3:執(zhí)行任務(wù)的時(shí)候:隊(duì)列不為空時(shí),我們先將元素取出來(lái),判斷是否到了執(zhí)行時(shí)間,沒(méi)到時(shí)間就放回去,放回去之后要加上 wait() 。那么加入新任務(wù)的時(shí)候也就相應(yīng)的要 notify() 避免讓 CPU 出現(xiàn)"空轉(zhuǎn)"的現(xiàn)象!!

?

🍁重點(diǎn)4:我們的加鎖不能只包裹?wait() ,notify(),否則會(huì)出現(xiàn)非原子性操作,從而導(dǎo)致線(xiàn)程安全問(wèn)題!!

?

經(jīng)過(guò)上述分析,我們發(fā)現(xiàn)多線(xiàn)程的代碼真的是防不勝防,稍微一點(diǎn)不注意,都可能引起線(xiàn)程安全問(wèn)題!!


總結(jié)

以上是生活随笔為你收集整理的实现定时器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。