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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

实现定时器

發布時間:2024/1/18 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实现定时器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

1.定時器是什么

2.標準庫中的定時器

3.實現定時器


1.定時器是什么

定時器也是軟件開發中的一個重要組件 . 類似于一個 " 鬧鐘 ". 達到一個設定的時間之后 , 就執行某個指定好的代碼。 🍃1.定時器是一種實際開發中非常常用的組件 . 🍃2.比如網絡通信中 , 如果對方 500ms 內沒有返回數據 , 則斷開連接嘗試重連 . 🍃3.比如一個 Map, 希望里面的某個 key 3s 之后過期 ( 自動刪除 ). 🍃4.類似于這樣的場景就需要用到定時器 .

2.標準庫中的定時器

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

🍁【注意事項】?

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

🍃2.將定時器和 sleep 做區分,sleep 是使當前線程處于阻塞狀態,而 定時器 只是記錄了多長時間后該執行的任務,中間的這些時間,當前線程該干嘛就干嘛。

🍃3.schedule 里面的 TimerTask 其實就相當于 Runnable,只不過是 TimerTask 實現了 Runnable 接口,在這里我們直接把它當成 Runnable 就好了。

3.實現定時器

通過觀察標準庫中的定時器,我們大概知道要怎么做了!!

🍃1. Timer 內部要組織很多的任務;

🍃2. Timer 里的每個任務都要通過一定的方式來描述出來;(自己定義一個 TimerTask

🍃3. 還需要有一個線程,通過這個線程來掃描定時器內部的任務,執行其中時間到了的任務。(Timer 內部的線程)

🍁【代碼實現】

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

【分析實現過程中的重點步驟】

🍁重點 1:使用優先級阻塞隊列將我們的任務組織起來!!

🍃1.雖然任務可能有很多,但是它們的執行順序是一定的,且按照時間順序先后來執行的,所以使用優先級隊列。

🍃2.在多線程環境下,這個隊列會被多個線程訪問,第一,schedule 可能是在多線程中被調用,每次調用都要往隊里添加元素;第二,定時器內部還需要有專門的線程來執行隊列里的任務。這些操作在多線程里都是存在線程安全問題的,所以需要使用到優先級阻塞隊列!!

🍁重點2:優先級阻塞隊列里的元素是一個引用類型(MyTask),所以我們需要指定比較規則,既可以讓 MyTask 實現 Comparable 接口,也可以在優先級阻塞隊列的構造方法中傳參,傳一個比較器 Comparator !!

🍁重點3:執行任務的時候:隊列不為空時,我們先將元素取出來,判斷是否到了執行時間,沒到時間就放回去,放回去之后要加上 wait() 。那么加入新任務的時候也就相應的要 notify() 避免讓 CPU 出現"空轉"的現象!!

?

🍁重點4:我們的加鎖不能只包裹?wait() ,notify(),否則會出現非原子性操作,從而導致線程安全問題!!

?

經過上述分析,我們發現多線程的代碼真的是防不勝防,稍微一點不注意,都可能引起線程安全問題!!


總結

以上是生活随笔為你收集整理的实现定时器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。