【Java多線程從青銅到王者】定時器的原理和實現(十一)

定時器

定時器時我們日常開發中會用到的組件工具,類似于一個"鬧鐘",設定一個時間,等到了時間,定時器最自動的去執行某個邏輯,比如博客的定時發布,就是使用到了定時器

Java標準庫里面也提供了定時器的實現
在這里插入圖片描述
在這里插入圖片描述
定義一個timer,添加多個任務,每個任務都帶有一個時間

定義任務的時候可以使用lambde表達式嗎?

  • 答案是不能的,lambde只能用于創建函數式接口的實例,如果非要用lambde表達式創建一個類的實例的話,可以用lambde先創建出一個函數式接口的實例,再把這個函數式接口賦值給類的變量,如下圖,我們的源代碼里面Timer就是一個實現了Runnable函數式接口的一個抽象類,是不可以使用lambde表達式的
    在這里插入圖片描述

內置了前臺線程

在這里插入圖片描述
我們上圖代碼的執行結果如下
在這里插入圖片描述
我們發現,控制臺打印了我們的三個任務以后,并沒有進程結束的提示,說明我們的進程并沒有結束,原因是Timer里面內置了前臺線程,它會阻止進程的結束

但是我們往timer里面添加的任務都執行完了,也不會結束嗎?

  • 因為我們的timer也不知道你是否還會添加新任務進來,所以它不能結束,必須嚴陣以待,也就是不能結束,于是內置了前臺線程

但是就沒有辦法讓timer結束嗎?

  • timer里面有一個cancel方法,可以手動調用來結束進程
    在這里插入圖片描述
    上述代碼我們調用了cancel后,進程會結束(如下圖)
    在這里插入圖片描述
    需要主動調用cancel讓線程主動結束,要不然Timer不知道是否還有其他地方要添加任務的

定時器的實現

我們先思考一下,實現一個定時器需要哪些的內容

  • 首先我們需要一個線程,幫助我們掐算時間,時間一到的話,這個線程就會執行該任務
  • 其次我們需要一個容器,能夠保存schedule進來的任務

我們直觀的來想的話,我們這個線程就要不斷的遍歷我們這個容器,看看任務的時間是否到了,如果到了,就執行這個任務
但是如果我們容器里面的元素很多呢?要是遍歷的話,時間復雜度就是o(n)了,開銷就很大了
我們此時就需要用到優先級隊列了,我們的每個任務都有實現,先執行時間小的,后執行時間大的,有了優先級隊列,必須是小根堆,隊首元素就是執行時間最小的元素,我們每次只需要看一下隊首元素是否到時間了,要是隊首元素也沒有到時間的話,其他的任務一定沒有到時間

我們現在的優先級隊列有兩個選擇:

  1. PriorityQueue(線程不安全)
  2. PriorityBloskingQueue(線程安全)

雖然PriorityBloskingQueue是線程安全的,但是我們這里要使用 PriorityQueue,使用PriorityBloskingQueue不太好控制,容易出問題,我們這里手動給PriorityQueue加鎖即可

在這里插入圖片描述
上面是我們寫的一個類,用來描述一個任務

我們這個類直接實現Runnable也是可以的,我們這里是讓這個類持有了Runnable

而且我們這個任務類是需要將其放到優先級隊列里面的,所以要求我們這個類是可以比較的,我們這里也實現了Comparable接口,并且重寫了CompareTo方法,這里的比較的規則就是時間的大小

如果是TreeSet和TreeMap的話我們要求元素是可以比較的,我們就需要實現Comparable和Comparator接口
如果是HsahSet和HashMap的話,就要求元素是可以比較相等的和可哈希的,這時候就要equals和hashCode方法了,有時候為了讓hsah更加高效的話,需要重寫這兩個方法

在這里插入圖片描述
這是我們寫的構造方法,在這里面我們創建了一個線程,這個線程就是我們的判斷和執行任務的線程

加鎖

由于我們的加入任務的操作(如下圖)和我們的執行并且刪除任務的操作都是對同一個隊列進行操作,可能會有線程安全問題
在這里插入圖片描述
可以發現我們都給這兩個方法加上鎖了
當我們線程如果發現隊列里面是空的,locker.wait就會釋放鎖,于是scedule就可以獲取到鎖了,獲取到鎖之后就可以往隊列里面添加任務,添加完任務之后,notify就可以將線程喚醒

在這里插入圖片描述
我們紅框部分的地方也要用到wait,是有時間限制的wait,這里有兩種情況:

  1. 我們能進入else就說明還沒有到首隊列元素的執行時間,此時我們需要等待(任務執行時間-當前時間)這么多的時間,等到了我們wait的時間,wait就會自動喚醒,再次進入循環取出隊首元素,發現到時間了,于是就執行任務,并且將任務從隊列里面刪除
  2. 我們進入else,執行wait釋放鎖并且阻塞的時候,此時又有一個任務通過schedule進入到了隊列,schedule里面的notify就會將我們的線程喚醒,線程喚醒之后又進入循環,由于我們加入了新的任務,這個新任務的時間有可能比我們原來的隊首任務的時間小,也有可能大,這時我們的隊首任務就會發生變化,于是又peek一下,取隊首元素,看看是否到了時間,在根據條件執行下面的邏輯

如果我們else里面什么都不加的話,只有一個coontinue,這時我的CPU只是在忙等,雖然在等,但是CPU很忙,因為此時線程的情況是進入了死循環,不如將CPU的資源讓出來,給其他的線程使用,這就是我們wait的另一個作用

使用sleep可以嗎?
不可以,sleep雖然也可以實現等待的結果,但是sleep沒有釋放鎖,如果我們中間有一個schedule又加入了一個任務,這個任務的執行時間是10:20:00,比如現在是10:00:00,我們的首隊列元素的執行時間是10:30:00,此時我們進入else執行到了sleep,按照我們上面wait的代碼,我們這里要sleep30分鐘,這個過程中,鎖沒有被釋放,是被判斷的線程持有的,這就導致我們的schedule方法獲取不到鎖,無法將新的任務添加到隊列,等sleep到了時間被喚醒的時候,已經過了10:20:00了,這個任務就錯過了

執行過程詳解

在這里插入圖片描述
執行到這里以后我們會進入到漫長的3s的等待,3s結束之后,wait就自動喚醒了
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/909248.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/909248.shtml
英文地址,請注明出處:http://en.pswp.cn/news/909248.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深入剖析AI大模型:Prompt 優化的底層邏輯

記得看到一篇NLP的文章,就 Prompt 時序效應的論文揭示了一個有趣現象,文章中說:模型對指令的解析存在 "注意力衰減" 特性 —— 就像人類閱讀時會更關注段落開頭,模型對 Prompt 前 20% 的內容賦予的權重高達 60%。這個發…

【備忘】PHP web項目一般部署辦法

【PHP項目一般部署辦法】 操作步驟 代碼: 把php項目代碼clone到指定位置如www/下新建php站點,填寫域名,把站點根目錄設置為項目根目錄項目入口設置,一般為public/項目權限改為766(特殊時候可設置為777),如果有特殊要求…

【60 Pandas+Pyecharts | 箱包訂單數據分析可視化】

文章目錄 🏳??🌈 1. 導入模塊🏳??🌈 2. Pandas數據處理2.1 讀取數據2.2 數據信息2.3 去除訂單金額為空的數據2.5 提取季度和星期 🏳??🌈 3. Pyecharts數據可視化3.1 每月訂單量和訂單金額分布3.2 各季…

玩轉Docker | 使用Docker部署vaultwarden密碼管理器

玩轉Docker | 使用Docker部署vaultwarden密碼管理器 前言一、vaultwarden介紹Vaultwarden 簡介主要特點二、系統要求環境要求環境檢查Docker版本檢查檢查操作系統版本三、部署vaultwarden服務下載vaultwarden鏡像編輯部署文件創建容器檢查容器狀態檢查服務端口安全設置四、配置…

晶振的多面舞臺:從日常電子到高精尖科技的應用探秘

在現代科技的宏大舞臺上,晶振宛如一位低調卻至關重要的幕后主角,以其穩定的頻率輸出,為各類電子設備賦予了精準的“脈搏”。從我們日常生活中須臾不離的電子設備,到引領時代前沿的高精尖科技領域,晶振都發揮著不可替代…

uni-app 小程序 Cannot read property ‘addEventListener‘ of undefined, mounted hook

在用 uni-app 開發微信小程序時,提示 Cannot read property addEventListener of undefined, mounted hook document.addEventListener("mousemove", this.touchmove) 在小程序開發里,addEventListener 并非通用的標準 API,不過與…

《專業小詞開課啦》——冪等

在系統對接過程中,當出現接口調用異常的情況時,程序員可能會用一些專業術語來答疑......對于0基礎同學,自然是需要自行百度一番,學習一下! 接下來,先學習【冪等】 PS: 小白參考1.1~1.4內容即…

滲透實戰PortSwigger Labs指南:自定義標簽XSS和SVG XSS利用

阻止除自定義標簽之外的所有標簽 先輸入一些標簽測試&#xff0c;說是全部標簽都被禁了 除了自定義的 自定義<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 當元素獲得焦點時&#xff08;如通過點擊或鍵盤導航&…

利用pycharm搭建模型步驟

1 如何將別人論文的代碼跑起來&#xff0c;以Pycharm為例&#xff0c;在下載代碼的時候&#xff0c;要注意使用的python版本是多少&#xff0c;并且要注意使用的keras和tensorflow等文件夾的版本&#xff0c;我們可以直接使用pycharm中file文件中的settings&#xff0c;來添加相…

Qt 中directoryChanged監聽某個目錄的內容是否發生變化

Qt 中&#xff0c;directoryChanged 是 QFileSystemWatcher 類的一個信號&#xff0c;用于監聽某個目錄的內容是否發生變化&#xff08;如添加、刪除文件或子目錄&#xff09; ? 一、功能說明 QFileSystemWatcher::directoryChanged(const QString &path) 信號的作用是&…

JavaWeb(Servlet預習)

案例1&#xff1a;基于jspServlet實現用戶登錄驗證 1.input.jsp <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset"UTF-8&q…

Docker Compose 部署 Prometheus + Grafana

安裝 docker-compose.yml version: 3.8services:# Prometheus 監控服務prometheus:image: prom/prometheus:latestcontainer_name: prometheusrestart: unless-stoppedvolumes:- ./conf/prometheus.yml:/etc/prometheus/prometheus.yml- ./prometheus_data:/prometheuscomman…

準確--使用 ThinBackup 插件執行備份和恢復

使用 ThinBackup 插件執行備份和恢復 導出&#xff08;備份&#xff09;步驟&#xff1a; 進入 Manage Jenkins > ThinBackup。設置 Backup schedule for full backups&#xff08;可選&#xff09;&#xff0c;并配置 Files to exclude&#xff08;可選&#xff09;。點擊…

Qt Creator 從入門到項目實戰

Qt Creator 簡介 Qt Creator 是一個跨平臺的集成開發環境&#xff08;IDE&#xff09;&#xff0c;專門用于開發 Qt 應用程序。它為開發者提供了一個強大的工具集&#xff0c;包括代碼編輯器、調試器、UI 設計器以及性能分析工具等。 1.1 Qt Creator 的安裝 Qt Creator 支持…

公司內網遠程訪問配置教程:本地服務器(和指定端口應用)實現外網連接使用

在數字化時代&#xff0c;企業的辦公模式日益多元化&#xff0c;遠程辦公、跨地區協作等需求不斷增加。這使得在公司內網中配置遠程訪問變得至關重要&#xff0c;它能讓員工無論身處何地&#xff0c;只要有網絡連接&#xff0c;就能便捷地訪問公司內部的各類資源&#xff0c;如…

邊緣計算如何重塑能源管理?從技術原理到應用場景全解析

在全球能源數字化轉型的浪潮中&#xff0c;一個看似不起眼的設備正在悄悄改變工業能效管理的模式 —— 這就是邊緣計算網關。以能源領域為例&#xff0c;傳統的 "設備 - 云端" 二層架構正面臨數據傳輸延遲、網絡帶寬壓力大、斷網失效等挑戰&#xff0c;而邊緣計算技術…

自主導航巡檢機器人系統解決方案

自主導航巡檢機器人系統解決方案 運動性能強大的通用型履帶式機器人底盤&#xff0c;整車采用克里斯蒂全獨立懸掛設計&#xff0c;內部搭載高扭矩無刷電機&#xff0c;通過精心匹配的底盤高度和功率配置&#xff0c;底盤表現出卓越的通過性能、低重心、平穩運行以及高效的傳動效…

Vim 撤銷 / 重做 / 操作歷史命令匯總

Vim 撤銷 / 重做 / 操作歷史命令匯總 Vim 提供了豐富的撤銷&#xff08;undo&#xff09;、重做&#xff08;redo&#xff09;及查看操作歷史的命令&#xff0c;幫助你在編輯過程中靈活地回退或前進到任意修改點。下面按功能分類整理常用命令&#xff0c;便于快速查閱和記憶。…

裝飾模式(Decorator Pattern)重構java郵件發獎系統實戰

前言 現在我們有個如下的需求&#xff0c;設計一個郵件發獎的小系統&#xff0c; 需求 1.數據驗證 → 2. 敏感信息加密 → 3. 日志記錄 → 4. 實際發送郵件 裝飾器模式&#xff08;Decorator Pattern&#xff09;允許向一個現有的對象添加新的功能&#xff0c;同時又不改變其…

項目四.高可用集群_ansible

設備準備 安裝wordpress [rootlocalhost ~]# nmcli c del "Wired connection 1" [rootlocalhost ~]# nmcli c add type ethernet ifname ens224 con-name ens224 ipv4.method manual ipv4.addr 192.168.88.40/24 gw4 192.168.88.1 autoconnect true [rootlocalhos…