【JAVA EE初階】多線程(1)

這樣的代碼,雖然也能打印hello thread,但是沒有創建新的線程,而是直接在main方法所在的主線程中執行了run的邏輯

start方法,是調用系統api,真正在操作系統內部創建一個線程。這個新的線程會以run作為入口方法(執行run)的邏輯,run方法,不需要在代碼中顯式調用

此處遇見受查異常為什么不能用throws呢?

因為,如果給run方法聲明加上throws,此時就意味著和父類Thread的run的方法聲明不一致,就無法構成方法重寫了。

package Thread;class MyThread extends Thread {@Overridepublic void run() {while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
}
public class Demo1 {
public static void main(String[] args) {System.out.println("你好!");// 創建并啟動MyThread線程MyThread myThread = new MyThread();myThread.start();// myThread.run();while(true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
}

輸出:

但是如果換成這樣的代碼:

package Thread;class MyThread extends Thread {@Overridepublic void run() {while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
}
public class Demo1 {
public static void main(String[] args) {System.out.println("你好!");// 創建并啟動MyThread線程MyThread myThread = new MyThread();// myThread.start();myThread.run();while(true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
}

輸出:

由此可見run方法并沒有創建一個新的進程,從始至終只有一個主線程在運行,只有將run的方法執行完才能去打印hello main 但是由于這里的 run方法是一個死循環,所以一直沒有打印hello main

通過觀察我們可以發現這里的main和thread的打印,并不是嚴格交替的。由于兩個打印,都加了sleep(1000)。當1000ms時間到的時候,這兩個線程哪一個限制性,這個順序是不確定的。

(操作系統調度線程的順序是無需,不可預測的,隨機的 )

可以通過Java jdk中的jconsole工具來觀察進程

我的jdk-jconsole工具目錄:C:\Program Files\Java\jdk-17\bin

折線圖

這張圖列出了當前進程中所有的線程。剩下的線程,都是JVM自帶的,這些線程進行了一些背后的操作,比如負責垃圾回收,記錄統計信息,記錄一些調試信息。

如果將Thread.start()改成Thread.run()——>

我們會發現剛剛的Thread0沒有了

一、Java中創建線程的方法

(1)創建子類,繼承Thread,重寫run,調用start

package Thread;class MyThread extends Thread {@Overridepublic void run() {while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
}
public class Demo1 {
public static void main(String[] args) {System.out.println("你好!");// 創建并啟動MyThread線程MyThread myThread = new MyThread();// myThread.start();myThread.run();while(true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
}

(2)創建子類,實現Runnable,重寫run,搭配Thread對象進行start

package Thread;class MyRunnable implements Runnable {@Overridepublic void run() {while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}public class Demo2 {public static void main(String[] args) {Runnable runnable = new MyRunnable();//runnable沒有start方法,所以不能直接調用run方法,需要將runnable對象作為參數傳遞給Thread類的構造方法,然后調用start方法啟動線程 Thread thread = new Thread(runnable);thread.start();}
}

使用Runnable描述線程要執行的任務是啥,真正去創建線程的工作,還是由Thread來負責。

interface是接口,不包含具體的方法的實現,只是提供一系列抽象方法,讓子類去重寫

*接口的的default一般不用,日常開發的時候,用到接口,都是希望全都提供抽象方法。除非是接口提供了一組方法,這一組方法中存在一些“公共的邏輯”,就可以在接口中搞default方法,使得這個方法表示公共邏輯,后面就可以在重寫其他抽象方法的時候去調用了。

對于第一種寫法(繼承Thread)描述任務的時候,任務代碼是寫到Thread子類中的,意味著任務內容和Thread類的耦合程度更高(*寫代碼要高內聚/低耦合)

未來如果想把這個任務給別的“主體”去執行(執行一個任務,線程只是其中一個選項,進程也可以,協程亦可以...)

第二種寫法,任務是寫到Runnable中的,幾乎不涉及到任何和“線程”相關的概念,任務內容和Thread概念的耦合是很小的,幾乎沒有

任務內容和Thread概念的耦合是很小的,幾乎沒有

后序就可以把這個任務交給進程、協程來執行

(*協程:近幾年提出的概念,可以理解為“輕量級線程”)

(3)繼承Thread,重寫run,調用start 通過匿名內部類

package Thread;public class Demo3 {public static void main(String[] args) {Thread t = new Thread() {@Overridepublic void run() {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}};t.start();}}

此處就是創建了沒有名字的匿名內部類,這個類就是Thread的子類,子類重寫了run方法,同時也創建了子類的實例,通過t引用指向。

(4)實現Runnable,重寫run,搭配Thread調用start 通過匿名內部類

package Thread;public class Demo4 {public static void main(String[] args) {Runnable runnable = new Runnable() {@Overridepublic void run() {while (true) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}};Thread t = new Thread(runnable);t.start();while(true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

(5)更簡單的寫法,基于lambda表達式創建線程

lambda表達式,本質上是“匿名方法”

package Thread;public class Demo5 {public static void main(String[] args) {Thread t = new Thread(()->{while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});t.start();while(true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

二、后臺線程與前臺線程

后臺線程:線程沒運行完,進程可以結束(線程不能夠組織進程結束)

前臺線程:線程沒有運行完,進程就不會結束(線程能夠組織進程結束)

main線程和我們自己創建的線程都是前臺線程,isDaemon = false;

剩下的線程就是后臺線程,isDaemon = true;(守護線程)

通過setDaemon設置線程為后臺(*必須在start之前set)

什么樣子的線程是前臺線程,什么樣子的線程是后臺線程呢?

如果一個線程做的任務很重要,這個任務必須要昨晚你,就應該設置這個線程為前臺線程

如果一個線程做的任務無關緊要/周期性無期限執行(比如說JVM的垃圾回收線程),就應該設置為后臺線程

package Thread;public class Demo5 {public static void main(String[] args) {Thread t = new Thread(()->{while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});t.setDaemon(true);t.start();//把t線程設置為守護線程,當main線程結束時,t線程也會結束for(int i = 0;i<3;i++){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

三、判斷線程是否存活

package Thread;public class Demo5 {public static void main(String[] args) {Thread t = new Thread(()->{while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}});System.out.println("t線程是否存活:"+t.isAlive());//false,t線程還沒有啟動,所以isAlive返回falset.setDaemon(true);t.start();//把t線程設置為守護線程,當main線程結束時,t線程也會結束System.out.println("t線程是否存活:"+t.isAlive());//true,t線程已經啟動,所以isAlive返回truefor(int i = 0;i<3;i++){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println("t線程是否存活:"+t.isAlive());//false,t線程已經結束,所以isAlive返回false}}

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

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

相關文章

javase 學習

一、Java 三大版本 javaSE 標準版 &#xff08;桌面程序&#xff1b; 控制臺開發&#xff09; javaME 嵌入式開發&#xff08;手機、小家電&#xff09;基本不用&#xff0c;已經淘汰了 javaEE E業級發開&#xff08;web端、 服務器開發&#xff09; 二、Jdk ,jre jvm 三…

【Linux】Linux 操作系統 - 05 , 軟件包管理器和 vim 編輯器的使用 !

文章目錄 前言一、軟件包管理器1 . 軟件安裝2 . 包管理器3 . Linux 生態 二、軟件安裝 、卸載三、vim 的使用1 . 什么是 vim ?2 . vim 多模式3 . 命令模式 - 命令4 . 底行模式 - 命令5. 插入模式6 . 替換模式7 . V-BLOCK 模式8 . 技巧補充 總結 前言 本篇筆者將會對軟件包管理…

python基礎知識點(1)

python語句 一行寫一條語句 一行內寫多行語句&#xff0c;使用分號分隔建議每行寫一句&#xff0c;且結束時不寫分號寫在[ ]、{ }內的跨行語句&#xff0c;被視為一行語句\ 是續行符,實現分行書寫功能 反斜杠表示下一行和本行是同一行 代碼塊與縮進 代碼塊復合語句&#xf…

C#/.NET/.NET Core技術前沿周刊 | 第 35 期(2025年4.14-4.20)

前言 C#/.NET/.NET Core技術前沿周刊&#xff0c;你的每周技術指南針&#xff01;記錄、追蹤C#/.NET/.NET Core領域、生態的每周最新、最實用、最有價值的技術文章、社區動態、優質項目和學習資源等。讓你時刻站在技術前沿&#xff0c;助力技術成長與視野拓寬。 歡迎投稿、推薦…

HTML表單與數據驗證設計

HTML 表單與數據驗證設計&#xff1a;構建可靠的用戶數據采集系統 引言 互聯網的核心是數據交互&#xff0c;而HTML表單是這一交互的主要入口。作為前端工程師&#xff0c;設計高質量的表單不僅關乎用戶體驗&#xff0c;更直接影響數據收集的準確性和系統安全。 在我的學習實…

基于STM32的Keil環境搭建與點燈

本人使用的STM32開發板為正點原子的STM32F103ZE&#xff0c;在此記錄完整的搭建與點燈過程。 一、Keil的安裝與配置 安裝Keil 首先進入Keil下載官網&#xff1a;https://www.keil.com/download/product/ 點擊MDK-ARM&#xff0c;并填寫相關信息&#xff0c;之后開始下載最新版…

React-useRef

如果我們想在hooks里面獲同步取最新的值&#xff0c;那么則可以使用useRef, 關鍵源碼如下&#xff1a; function mountRef<T>(initialValue: T): {|current: T|} {const hook mountWorkInProgressHook();const ref {current: initialValue};hook.memoizedState ref;re…

幽靈依賴與常見依賴管理

文章目錄 前言1. 演示&#xff1a;檢測和修復幽靈依賴步驟1&#xff1a;安裝 depcheck步驟2&#xff1a;在項目根目錄運行 depcheck可能的輸出步驟3&#xff1a;修復幽靈依賴 2. 依賴管理的好習慣 1. 場景設定現在有如下依賴需求&#xff1a; 2. 依賴沖突的表現3. 解決依賴沖突…

如何使用人工智能大模型,免費快速寫工作總結?

如何使用人工智能大模型&#xff0c;免費快速寫工作總結&#xff1f; 詳細學習視頻https://edu.csdn.net/learn/40406/666581

[Java實戰經驗]異常處理最佳實踐

一些好的異常處理實踐。 目錄 異常設計自定義異常為異常設計錯誤代碼&#xff08;狀態碼&#xff09;設計粒度全局異常處理異常日志信息保留 異常處理時機資源管理try-with-resources異常中的事務 異常設計 自定義異常 自定義異常設計&#xff0c;如業務異常定義BusinessExce…

Makefile 入門指南

Makefile 入門指南 最簡單的例子 單文件編譯 假設我們有一個main.cpp文件&#xff0c;最簡單的Makefile如下&#xff1a; # 最簡單的單文件編譯 # 目標:依賴文件 main: main.cpp# 編譯命令g main.cpp -o main使用步驟&#xff1a; 將上述內容保存為名為Makefile的文件&…

PyTorch數據操作基礎教程:從張量創建到高級運算

本文通過示例代碼全面講解PyTorch中張量的基本操作&#xff0c;包含創建、運算、廣播機制、索引切片等核心功能&#xff0c;并提供完整的代碼和輸出結果。 1. 張量創建與基本屬性 import torch# 創建連續數值張量 x torch.arange(12, dtypetorch.float32) print("原始張…

【Redis】Redis中的常見數據類型(一)

文章目錄 前言一、Redis前置知識1. 全局命令2、數據結構和內部編碼3. 單線程架構 二、String 字符串1. 常見命令2. 計數命令3.其他命令4. 內部編碼5. 典型使用場景 三、Hash哈希1. 命令2.內部編碼3. 使用場景4. 緩存方式對比 結語 前言 Redis 提供了 5 種數據結構&#xff0c;…

Windows 中使用 `netstat` 命令查看端口占用

在 Windows 系統中&#xff0c;可以通過 netstat 命令來查看當前系統的網絡連接以及端口的占用情況。以下是關于該命令的具體說明&#xff1a; #### 使用方法 1. **查看所有端口及其狀態** 可以通過以下命令查看系統中的所有活動連接和監聽端口&#xff1a; bash net…

23種設計模式-結構型模式之裝飾器模式(Java版本)

Java 裝飾器模式&#xff08;Decorator Pattern&#xff09;詳解 &#x1f381; 什么是裝飾器模式&#xff1f; 裝飾器模式是一種結構型設計模式&#xff0c;允許向一個對象動態添加新的功能&#xff0c;而不改變其結構。 &#x1f9f1; 你可以想象成在原有功能上“包裹”一…

解決模擬器打開小紅書設備異常問題

解決模擬器打開小紅書設備異常問題 解決模擬器打開小紅書設備異常問題和無法打開問題 解決模擬器打開小紅書設備異常問題和無法打開問題 問題描述 最近有用戶反饋在模擬器上無法正常登錄和打開小紅書APP&#xff0c;系統提示"設備異常"錯誤。本文將詳細介紹如何通過…

論文閱讀:2025 arxiv AI Alignment: A Comprehensive Survey

總目錄 大模型安全相關研究&#xff1a;https://blog.csdn.net/WhiffeYF/article/details/142132328 AI Alignment: A Comprehensive Survey 人工智能對齊&#xff1a;全面調查 https://arxiv.org/pdf/2310.19852 https://alignmentsurvey.com/ https://www.doubao.com/cha…

精益數據分析(1/126):從《精益數據分析》探尋數據驅動增長之道

精益數據分析&#xff08;1/126&#xff09;&#xff1a;從《精益數據分析》探尋數據驅動增長之道 在當今數字化時代&#xff0c;數據無疑是企業發展的關鍵驅動力&#xff0c;對于競爭激烈的程序化廣告行業更是如此。最近我在研讀《精益數據分析》這本書&#xff0c;收獲頗豐&…

第五節:React Hooks進階篇-如何用useMemo/useCallback優化性能

反模式&#xff1a;濫用導致的內存開銷React 19編譯器自動Memoization原理 React Hooks 性能優化進階&#xff1a;從手動到自動 Memoization &#xff08;基于 React 18 及以下版本&#xff0c;結合 React 19 新特性分析&#xff09; 一、useMemo/useCallback 的正確使用場景…

windows server C# IIS部署

1、添加IIS功能 windows server 2012、windows server 2016、windows server 2019 說明&#xff1a;自帶的是.net 4.5 不需要安裝.net 3.5 盡量使用 windows server 2019、2016高版本&#xff0c;低版本會出現需要打補丁的問題 2、打開IIS 3、打開iis應用池 .net 4.5 4、添…