javaEE初階————多線程初階(5)

本期是多線程初階的最后一篇文章了,下一篇就是多線程進階的文章了,大家加油!

一,模擬實現線程池

我們上期說過線程池類似一個數組,我們有任務就放到線程池中,讓線程池幫助我們完成任務,我們該如何實現線程池呢,我們來想一想線程的構造方法,第一個參數是核心線程數,第二個是最大線程數,這個我們不考慮,第三個是最大空閑時間,第四個事枚舉的時間類型,第五個是阻塞隊列,完了是工廠模式,之后是拒絕策略;

我們來模擬一下;

package Demo1;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;public class MyThreadPool {private BlockingQueue<Runnable> queue = null;public MyThreadPool(int n){queue = new ArrayBlockingQueue<>(n);for (int i = 0; i < n; i++) {Thread t  = new Thread(()->{while(true){try {queue.take().run();} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();}}public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}
}

我們先來看這段代碼,我們先起了類名MyThreadPool,在類中先弄了一個未初始化的阻塞隊列,在創建構造方法,由傳入的數字來創建阻塞隊列的容量也就是線程池中有幾個線程,我們根據傳入的數字n來創建n個線程,讓n個線程循環往復的到阻塞隊列中去哪任務,還有submit方法,我們讓將拿到的任務添加到阻塞隊列中去,我們來測試代碼;?

public class test {public static void main(String[] args) throws InterruptedException {MyThreadPool pool = new MyThreadPool(4);for (int i = 0; i < 50; i++) {int id = i;pool.submit(()->{System.out.println(id + " and " + 123456);});}}
}

我們創建了50個任務,讓線程池來完成,我們看看運行結果;

我們看到線程隨機執行了我們的任務;

最后是沒有結束的啊,沒有正常的返回值,這是因為我new thread創建的線程是前臺線程,那幾個線程還在阻塞著等待任務呢,我們想要結束應該把他們設置為后臺線程才行;

———————————————————————————————————————————

二,定時器詳解

定時器是什么,定時器也是軟件開發中的一個重要組件,它有什么用的,大家使用瀏覽器的時候有沒有發生過連接斷開或者未響應之類的情況,其實這就是定時器在發揮,如果沒有定時器的話就會一直請求,但是沒準這次的請求就不會得到響應,為了不發生無休止的等待,我們就使用定時器來中斷這次請求,既然響應不了那就直接結束;

那么我們如何使用定時器呢?

標準庫中提供了Timer類,Timer類中包含一個schedule方法,我們使用schedule方法來使用定時器功能,schedule方法中有兩個參數,一個是需要執行的任務;

schedule(new TimerTask(抽象類,繼承了Runnable接口),時間);

我們來用代碼展示一下;

import java.util.Timer;
import java.util.TimerTask;public class test {public static void main(String[] args) throws InterruptedException {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("1s后   任務1");}},1000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("3s后   任務2");}},3000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("5s后   任務3");}},5000);Thread.sleep(7000);timer.cancel();}
}

?我們給Timer三個任務讓他在規定時間段運行,并最終終止Timer線程,我們來看運行效果;

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

另外,Timer其實已經過時,

我推薦使用更強的scheduledExecutorService,Timer是單線程的,但是scheduledExecutorService是線程池,功能更強,我們來說說用法;

1,延遲執行任務

schedule(Runnable command,long delay,TimeUnit unit)

第一個參數是任務,就是接口就行,第二個參數是時間,意思是多長時間執行任務,達到延遲效果,第三個參數是時間類型,也就是枚舉類型;

我們來上代碼;

這是第三個參數枚舉類型,提供了很多的枚舉;

?

public class Test2 {public static void main(String[] args) {ScheduledExecutorService sr = Executors.newScheduledThreadPool(1);sr.schedule(()->{System.out.println("2秒后    打印");},2, TimeUnit.SECONDS);sr.schedule(()->{System.out.println("4秒后    打印");},4,TimeUnit.SECONDS);sr.shutdown();}
}

我們使用shutdown方法來關閉調度器,來看運行結果;

程序正常結束了;

2,定期執行任務

scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)

第一個參數還是接口任務,第二個參數是初始延遲時間,第三個參數是任務執行的時間間隔,最后一個參數還是時間的枚舉類型;

我們來上代碼;

public class Demo2 {public static void main(String[] args) throws InterruptedException {ScheduledExecutorService service = Executors.newScheduledThreadPool(1);service.scheduleAtFixedRate(()->{System.out.println("任務執行了");},1,2, TimeUnit.SECONDS);Thread.sleep(10000);service.shutdown();}
}

??

還有一種固定時間延遲執行任務,跟這個是基本一樣的,

schedulewithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)

第一個參數還是接口任務,第二個參數是初始延遲時間,第三個參數是任務執行的延遲時間,最后一個參數還是時間的枚舉類型;

?

public class Demo3 {public static void main(String[] args) throws InterruptedException {ScheduledExecutorService service = Executors.newScheduledThreadPool(1);service.scheduleWithFixedDelay(()->{System.out.println("任務執行了");},1,2, TimeUnit.SECONDS);Thread.sleep(10000);service.shutdown();}
}

?這兩個有啥區別呢,感覺是很像的,第一個scheduleAtFixedRate是延遲一定時間后按固定的時間來執行,這個是嚴格執行的,不會根據任務執行的時間來往后推,如果這個任務執行了1s那么距離規定的時間就還剩1s了,如果使用schedulewithFixedDelay的就是延遲執行,如果我們這個任務執行了1s那么距離執行下一個任務的時間還是2s,另外scheduledExecutorService因為是基于線程池實現,所以在發生異常時是不會終止的,而單線程的Timer是會隨著異常而終止的;

講了這么多了,我們來模擬實現一下定時器吧,

首先為我們來思考一下怎么實現呢,我們要創建一個MyTimer類,其中包含我們要使用的優先級隊列,我們來實現Schedule方法,實現將任務和要執行的時間,還要實現Mytimer中有線程來執行任務,之后還有實現任務類,我們來試試;

1,先來任務類:

public class TimerTask implements Comparable<TimerTask>{private long time;private Runnable task;public TimerTask(long time,Runnable runnable){this.time = time;this.task = runnable;}@Overridepublic int compareTo(TimerTask o) {return (int)(this.time-o.time);}public void run(){task.run();}public long getTime(){return time;}
}

任務類中有記錄的時間long類型的time,一個Runnable任務,在任務初始化的時候把時間和任務都初始化了,實現run方法和getTime方法,在實現comparable接口為了優先級隊列做準備,我們想要把小的時間先執行,再來MyTimer


public class MyTimer {private PriorityQueue<TimerTask> priorityQueue = new PriorityQueue<>();Object locker = new Object();public void schedule(Runnable runnable,long time){TimerTask timerTask = new TimerTask(System.currentTimeMillis()+time,runnable);synchronized (locker){priorityQueue.offer(timerTask);locker.notify();}}public MyTimer(){Thread t = new Thread(()->{while(true){synchronized (locker){while(priorityQueue.isEmpty()){try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}TimerTask task = priorityQueue.peek();if (task.getTime()>System.currentTimeMillis()){try {locker.wait(task.getTime()-System.currentTimeMillis());} catch (InterruptedException e) {throw new RuntimeException(e);}}else{task.run();priorityQueue.poll();}}}});t.start();}
}

初始化一個優先級隊列,大堆還是小堆要在TimerTask中的compareTo中修改,實現schedule方法,創建一個任務對象,參數的任務用傳入的,時間用當前入隊列的時間戳加上傳入的時間,之后將任務放到隊列中去,因為優先級隊列是不安全的,我們要在入隊列的時候加鎖,接下來就是線程,我們在MyTimer構造方法中,創建一個線程,之后讓線程循環的去隊列中取得任務,這里因為還是涉及優先級隊列,所以我們還是要加鎖,我們要循環判斷隊列是否為空,為啥要使用循環,因為要避免入隊列操作的notify喚醒當前的wait之后,另一個線程搶先執行了任務,但是當前的線程就會去peek空的隊列了,所以我們循環判斷,就是為了要避免誤喚醒,我們在拿到了任務之后,如果當前時間還沒到我們要執行的時間我們就用wait(定時)來等待指定時間來繼續執行,我們這里不用sleep,之前說過,我們基本是不會使用sleep的因為sleep會抱著鎖睡,雖然不占用Cpu資源了,但是就這么停著,不符合我們預期的;

public class test {public static void main(String[] args) throws InterruptedException {MyTimer myTimer = new MyTimer();myTimer.schedule(()->{System.out.println("已經過了2秒 執行任務");},2000);myTimer.schedule(()->{System.out.println("已經過了5秒 執行任務");},5000);}
}

我們來測試一下;

自己觀察一下,會根據時間來運行的,本期文章就到這里啦;

大家繼續加油!

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

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

相關文章

工業AR眼鏡的‘芯’動力:FPC讓制造更智能【新立電子】

隨著增強現實&#xff08;AR&#xff09;技術的快速發展&#xff0c;工業AR智能眼鏡也正逐步成為制造業領域的重要工具。它不僅為現場工作人員提供了視覺輔助&#xff0c;還極大地提升了遠程協助的效率、優化了倉儲管理。FPC在AI眼鏡中的應用&#xff0c;為工業AR智能眼鏡提供了…

FPGA開發,使用Deepseek V3還是R1(5):temperature設置

以下都是Deepseek生成的答案 FPGA開發&#xff0c;使用Deepseek V3還是R1&#xff08;1&#xff09;&#xff1a;應用場景 FPGA開發&#xff0c;使用Deepseek V3還是R1&#xff08;2&#xff09;&#xff1a;V3和R1的區別 FPGA開發&#xff0c;使用Deepseek V3還是R1&#x…

網站內容更新后百度排名下降怎么辦?有效策略有哪些?

轉自 網站內容更新后百度排名下降怎么辦&#xff1f;有效策略有哪些&#xff1f; 網站內容更新是促進網站優化的關鍵環節&#xff0c;但是頻繁修改網站內容會對網站的搜索引擎排名造成很大的影響。為了保持網站排名&#xff0c;我們需要采取一些措施來最小化對百度排名的影響。…

安裝 cpolar 內網穿透工具的步驟

安裝 cpolar 內網穿透工具的步驟 1. 下載 cpolar 軟件安裝包 步驟&#xff1a; 前往 cpolar 官方下載頁面。 根據您的操作系統&#xff08;Windows、macOS、Linux 等&#xff09;&#xff0c;選擇對應的安裝包進行下載。 2. 注冊 cpolar 賬號 步驟&#xff1a; 訪問 cpolar…

Linux :進程狀態

目錄 1 引言 2 操作系統的資源分配 3進程狀態 3.1運行狀態 3.2 阻塞狀態 3.3掛起狀態 4.進程狀態詳解 4.1 運行狀態R 4.2 休眠狀態S 4.3深度睡眠狀態D 4.4僵尸狀態Z 5 孤兒進程 6 進程優先級 其他概念 1 引言 &#x1f33b;在前面的文章中&#xff0c;我們已…

openwebUI訪問vllm加載deepseek微調過的本地大模型

文章目錄 前言一、openwebui安裝二、配置openwebui環境三、安裝vllm四、啟動vllm五、啟動openwebui 前言 首先安裝vllm&#xff0c;然后加載本地模型&#xff0c;會起一個端口好。 在安裝openwebui,去訪問這個端口號。下面具體步驟的演示。 一、openwebui安裝 rootautodl-co…

DeepSeek-V3:AI語言模型的高效訓練與推理之路

參考&#xff1a;【論文學習】DeepSeek-V3 全文翻譯 在人工智能領域&#xff0c;語言模型的發展日新月異。從早期的簡單模型到如今擁有數千億參數的巨無霸模型&#xff0c;技術的進步令人矚目。然而&#xff0c;隨著模型規模的不斷擴大&#xff0c;訓練成本和推理效率成為了擺在…

Spring單例模式 Spring 中的單例 餓漢式加載 懶漢式加載

目錄 核心特性 實現方式詳解 1. 餓漢式&#xff08;Eager Initialization&#xff09; 2. 懶漢式&#xff08;Lazy Initialization&#xff09; 3. 靜態內部類&#xff08;Bill Pugh 實現&#xff09; 4. 枚舉&#xff08;Enum&#xff09; 破壞單例的場景及防御 Sprin…

DeepSeek MLA(Multi-Head Latent Attention)算法淺析

目錄 前言1. 從MHA、MQA、GQA到MLA1.1 MHA1.2 瓶頸1.3 MQA1.4 GQA1.5 MLA1.5.1 Part 11.5.2 Part 21.5.3 Part 3 結語參考 前言 學習 DeepSeek 中的 MLA 模塊&#xff0c;究極縫合怪&#xff0c;東抄抄西抄抄&#xff0c;主要 copy 自蘇神的文章&#xff0c;僅供自己參考&#…

uniapp 中引入使用uView UI

文章目錄 一、前言&#xff1a;選擇 uView UI的原因二、完整引入步驟1. 安裝 uView UI2. 配置全局樣式變量&#xff08;關鍵&#xff01;&#xff09;3. 在 pages.json中添加&#xff1a;4. 全局注冊組件5. 直接使用組件 五、自定義主題色&#xff08;秒換皮膚&#xff09; 一、…

zookeeper-docker版

Zookeeper-docker版 1 zookeeper概述 1.1 什么是zookeeper Zookeeper是一個分布式的、高性能的、開源的分布式系統的協調&#xff08;Coordination&#xff09;服務&#xff0c;它是一個為分布式應用提供一致性服務的軟件。 1.2 zookeeper應用場景 zookeeper是一個經典的分…

【量化金融自學筆記】--開篇.基本術語及學習路徑建議

在當今這個信息爆炸的時代&#xff0c;金融領域正經歷著一場前所未有的變革。傳統的金融分析方法逐漸被更加科學、精準的量化技術所取代。量化金融&#xff0c;這個曾經高不可攀的領域&#xff0c;如今正逐漸走進大眾的視野。它將數學、統計學、計算機科學與金融學深度融合&…

unity學習56:舊版legacy和新版TMP文本輸入框 InputField學習

目錄 1 舊版文本輸入框 legacy InputField 1.1 新建一個文本輸入框 1.2 InputField 的子物體構成 1.3 input field的的component 1.4 input Field的屬性 2 過渡 transition 3 控件導航 navigation 4 占位文本 placeholder 5 文本 text 5.1 文本內容&#xff0c;用戶…

汽車電子電控軟件開發中因復雜度提升導致的架構惡化問題

針對汽車電子電控軟件開發中因復雜度提升導致的架構惡化問題&#xff0c;建議從以下方向進行架構優化和開發流程升級&#xff0c;以提升靈活性、可維護性和擴展性&#xff1a; 一、架構設計與模塊化優化 分層架構與模塊解耦 采用AUTOSAR標準的分層架構&#xff08;應用層、運行…

【彈性計算】彈性裸金屬服務器和神龍虛擬化(一):功能特點

彈性裸金屬服務器和神龍虛擬化&#xff08;一&#xff09;&#xff1a;功能特點 特征一&#xff1a;分鐘級交付特征二&#xff1a;兼容 VPC、SLB、RDS 等云平臺全業務特征三&#xff1a;兼容虛擬機鏡像特征四&#xff1a;云盤啟動和數據云盤動態熱插拔特征五&#xff1a;虛擬機…

騰訊云大模型知識引擎驅動的DeepSeek滿血版醫療顧問大模型搭建實戰

文章目錄 1. 引言2. 什么是騰訊云大模型知識引擎&#xff08;LKE&#xff09;&#xff1f;核心優勢功能特點應用場景 3. 模型搭建過程3.1 注冊登錄產品3.2 創建應用3.3 配置模型3.4 配置角色指令3.5 配置歡迎語3.6 配置知識庫3.7 配置工作流3.8 啟用聯網搜索3.9 發布模型 4. 問…

nio中ByteBuffer使用

創建ByteBuffer ByteBuffer buffer ByteBuffer.allocate(10);// 字符串轉 bytebufferByteBuffer buffer01 Charset.defaultCharset().encode("hello world"); ByteBuffer buffer02 ByteBuffer.wrap("hello".getBytes()); ByteBuffer buffer03 Standard…

如何在 IntelliJ IDEA 中集成 DeepSeek

如何在 IntelliJ IDEA 中集成 DeepSeek 在本教程中&#xff0c;我們將帶您一步步完成將 DeepSeek 集成到 IntelliJ IDEA 中的過程。通過此集成&#xff0c;您可以在IDE中利用DeepSeek強大的功能&#xff0c;提高開發工作效率。 步驟 1&#xff1a;安裝 Proxy AI 插件 首先&a…

【Maven】入門介紹 與 安裝、配置

文章目錄 一、Maven簡介1. Maven介紹2. Maven軟件工作原理模型圖 二、Maven安裝和配置1. Maven安裝2. Maven環境配置3. Maven功能配置4. IDEA配置本地Maven軟件 一、Maven簡介 1. Maven介紹 https://maven.apache.org/what-is-maven.html Maven 是一款為 Java 項目管理構建、…

Java數據結構第十六期:走進二叉樹的奇妙世界(五)

專欄&#xff1a;Java數據結構秘籍 個人主頁&#xff1a;手握風云 目錄 一、非遞歸實現遍歷二叉樹 1.1. 二叉樹的前序遍歷 1.2. 二叉樹的中序遍歷 1.3. 二叉樹的后序遍歷 一、非遞歸實現遍歷二叉樹 1.1. 二叉樹的前序遍歷 我們這里要使用棧來進行實現。我們反向思考一下為…