多線程Thread(初階二:Thread類及常??法)

目錄

一、Thread 的常?構造?法

繼承Thread代碼:

實現Runnable接口代碼:

二、Thread 的?個常?屬性

1、id:

2、獲取線程的名字。

3、進程的狀態:

4、在java中設置的優先級,

5、是否后臺線程,

6、是否存活,

7、是否中斷,

8、等待線程(結束),

9、獲取線程的引用,currentThread()


一、Thread 的常?構造?法

最后一個線程組的概念是java的概念,和系統中的線程組不一樣,不是同一個東西。

第一個和第二個構造方法在初階一有介紹,

鏈接:多線程Thread(初階一:認識線程)-CSDN博客

第三是創建一個線程,并且可以給這個線程命名,并不是它默認的Thread-0 / 1 / 2.....,第四個也是可以給線程對象命名,不過是使用接口的方法。

繼承Thread代碼:

class MyThread extends Thread {@Overridepublic void run() {System.out.println("hello thread1");}String name;public MyThread(String name) {super(name);this.name = name;}
}
public class ThreadDemo1 {public static void main(String[] args) {Thread t1 = new MyThread("這是我的線程");t1.start();Thread t2 = new Thread("這是我的線程"){@Overridepublic void run() {System.out.println("hello thread2");}};t2.start();}
}

執行效果:

兩個線程:

上面兩種的兩種創建線程方式都可以。

實現Runnable接口代碼:

class MyThread2 extends Thread {String name;public MyThread2(String name) {super(name);this.name = name;}@Overridepublic void run() {System.out.println("hello thread1");}
}
public class TestDemo2 {public static void main(String[] args) {Thread t1 = new MyThread2("這是我的線程1");t1.start();Thread t2 = new Thread("這是我的進程2") {@Overridepublic void run() {System.out.println("hello thread2");}};t2.start();}
}

執行效果:

兩個線程:

注意:我們創建的線程如果不起名字,默認是Thread-0 1 2 3....,給不同線程起不同名字,對于線程的執行,沒啥影響,主要是為了方便調試;線程之間的名字是可以重復的,在同一個工作中,需要多個線程完成,都可以起一樣的名字;但是名字也不要亂起,最后要有一定的描述性。


二、Thread 的?個常?屬性

1、id

jvm自動分配的身份標識,會保證唯一性。

2、獲取線程的名字。

3、進程的狀態

就緒狀態、阻塞狀態;線程也有狀態,Java中對線程的狀態進行了進一步的區分(比系統原生的狀態更豐富一些)。

4、在java中設置的優先級

效果不是很明顯,因為系統是隨機調度的(對內核的調度器調度過程會產生一些影響)。

5、是否后臺線程

也稱為是否守護線程(比較抽象),所以記住和理解是否后臺線程會輕松一些,與此相反,也有前臺線程(和Android上的前臺app,后臺app完全不同)。

后臺線程和前臺線程的區別前臺線程的運行,會阻止進程結束

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?后臺線程的運行,不會阻止進程結束

我們創建的線程,默認是前臺進程。

如下代碼:

public class TestDemo3 {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) {throw new RuntimeException(e);}}}};t.start();}
}

執行效果:會不停的輸出打印hello thread

那我們試著把這個線程設置為后臺線程試試(默認為前臺),代碼:

public class TestDemo3 {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) {throw new RuntimeException(e);}}}};//在start之前,設置線程為后臺線程(不能在start之后設置)t.setDaemon(true);t.start();}
}

執行效果:

根本就沒有打印hello thread,進程就結束了,因為是后臺進程,不會阻止進程的結束。

設為true是后臺,后臺,可以理解為背后,不出面的人,你感知不到;后臺不會阻止進程結束。

不設為true是前臺,前臺,可以理解為明面上的人,你能感知到;前臺會阻止進程結束。

6、是否存活,

isAlive( )表示內核中的線程(PCB)是否還存在。java代碼中定義的線程對象(Thread)實現,雖然是表示一個線程,但這個對象本身的生命周期,和內核中的PCB生命周期? ,是不完全一樣的。

isAlive的測試,代碼:

public class TestDemo4 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}});System.out.println("start之前:" + t.isAlive());t.start();System.out.println("start之后" + t.isAlive());Thread.sleep(2000);System.out.println("t結束之后" + t.isAlive());}
}

執行效果:

解釋:啟動線程之前,也就是start之前,t這個實例線程是還沒開始的,所以isAlive返回的是false,start后就查看這個線程存不存在,因為線程也剛啟動,所以isAlive返回的是true,休眠兩秒之后,t線程已經跑完了,所以isAlive返回的也是false。

7、是否中斷

也是終止的意思。

下面寫一個代碼,用boolean類型的變量來控制while循環,也起到終止線程的作用。

public class ThreadDemo1 {private static boolean isQuit = false;public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!isQuit) {System.out.println("我是一個線程,正在工作");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("線程工作完畢");});t.start();Thread.sleep(3000);System.out.println("讓線程結束");isQuit = true;}
}

注意:這里的isQuit變量放在類中,不放在方法里作為局部變量的原因是涉及到了變量捕獲如果放在main方法里,是局部變量,就必須要加 final 修飾將其變成常量為什么呢?這時因為main線程和我們創建的線程的棧幀生命周期不同,如果main線程先結束了,我們創建的線程要獲取這個變量,但是我們main線程的棧幀生命周期已經結束了,我們拿不到這個變量,java這里的做法就比較暴力,直接把這個變量變成常量,要么這個變量就是全局變量,以至于不會發生上面的情況。

執行效果:

這時,我們也可以使用jdk里自帶的方法:isInterrupted( )

代碼如下:

public class ThreadDemo2 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("我是一個線程,正在工作");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("線程執行完畢");});t.start();Thread.sleep(3000);System.out.println("讓線程結束");t.interrupt();}
}

執行效果:

這個線程并不會結束,會繼續執行。

解釋:可以看到這里拋出了個異常,而這個異常是InterruptedException 異常

如果沒有sleep,interrupt是可以讓線程順利結束的,但是有了sleep就會引起變數。

這說明,sleep這出現問題了,為什么呢?原因是這個線程還在執行,main線程休眠3秒后,終止了這個線程,但sleep還沒休眠夠1秒,這里就會提前喚醒。

這里,提前喚醒,會做兩件事:

1、拋出?InterruptedException (緊接著就會被catch獲取到)。

2、清除?Thread 對象的 isInterrupt 標志位。(sleep清空標志位,是為了給程序猿更多的“可操作性空間”)。

所以,interrupt已經把標志位設置為true了,sleep被提前喚醒,清除了isInterrupt標志位后,就又把標志位設回了false,這個while循環還是能進去的,所以線程還在繼續執行。

此時,程序猿就可以在catch語句中加入一些代碼,來做一些處理:

1、讓線程立即結束。(加上break)

2、讓線程不結束,繼續執行。(不加break)

3、讓線程執行一些邏輯后,再結束。(寫一些其他代碼,再加break)

對于一個服務器程序來說,穩定性很重要,這些所謂的“問題”,在java中就會以異常的形式體現出來,可以通過catch語句,對這些異常進行處理。主要的幾種處理方式:

1、嘗試自動恢復

2、記錄日志

3、發出警報

8、等待線程(結束),

join( )。我們知道,多線程的執行順序是不同的(隨機調度,搶占式執行),有不可預期性,雖然線程的調度是無序的,但是我們可以調用一些api,來影響帶線程的執行順序,join就是一種方式,影響 線程結束 的先后順序。比如:t2 線程等待 t1,這時,一定是 t1先結束,t2 后結束。這里的join就會使 t2 線程阻塞。

代碼:

public class ThreadDemo3 {public static void main(String[] args) {Thread t = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("我是一個線程,正在工作");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("線程結束");});t.start();//t.join();System.out.println("這時一個主線程,在t線程結束后再執行");}
}

我們想讓t線程執行完后再執行主線程,如果不寫join方法。因為多線程的調度是隨機性的,執行效果如下:

執行效果和我們預期的不一樣,加上join方法后,

代碼:

public class ThreadDemo3 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("我是一個線程,正在工作");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("線程結束");});t.start();t.join();System.out.println("這時一個主線程,在t線程結束后再執行");}
}

執行效果:

結果和我們想要預期效果相同。這里的join的意思是:讓 t 線程執行完,再執行本線程。

這里是讓main線程主動放棄去調度器調度,t 線程執行完后,main線程才執行,這也代表哪個線程調用join,哪個線程就是阻塞等待。這里就有了先后順序。

注意:這里的先后順序和優先級不同,優先級是系統調度器,在內核中完成的工作,即使優先級有差異,但是每個線程的執行順序還是隨機的(控制不了)。

等待線程結束還有兩個重載方法,里面放的是要等待的時間,如圖:

如果join不加參數,就是死等,第一個加參數的就是:等待多少毫秒,第二個加參數:數值精確到納秒,不過很少用,因為計算機精確不到這么小。加參數是帶有時間的等。

注意,有時候不想等,我們也可以不等,例如加 interrupt,可以終止這個等待,我們也可以在idea看到join的實現,是throws了?InterruptedException的。

9、獲取線程的引用,currentThread()

我們對于一個類繼承Thread是可以通過this拿到線程的實例的,

代碼如下:

class MyThread extends Thread {@Overridepublic void run() {System.out.println("id:"+ this.getId() + " name:" + this.getName());}
}
public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();}
}

效果如下:

但是,如果是接口或者我們使用匿名內部類 / lambda表達式,就不能獲取到Thread的引用了,這時,Thread已經給我們提供了方法獲取引用了:Thread.currentThread()。如下展示:

代碼:

public class ThreadDemo2 {public static void main(String[] args) {Thread t1 = new Thread(() -> {Thread t = Thread.currentThread();System.out.println(t.getId());});Thread t2 = new Thread(() -> {Thread t = Thread.currentThread();System.out.println(t.getName());});t1.start();t2.start();}
}

效果如下:


都看到這了,點個贊再走吧,謝謝謝謝謝!!!

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

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

相關文章

ubuntu22.04 arrch64版在線安裝node

腳本 #安裝node#下載node、npm國內鏡像&#xff08;推薦&#xff09;# 判斷是否安裝了nodeif type -p node; thenecho "node has been installed."elsemkdir -p /home/zenglg cd /home/zenglgwget https://registry.npmmirror.com/-/binary/node/v10.14.1/node-v10.…

Linux系統編程 day04 文件和目錄操作

Linux系統編程 day04 文件和目錄操作 1. 文件IO1.1 open 函數1.2 close函數1.3 read函數1.4 write函數1.5 lseek函數1.6 errno變量1.7 文件示例1 讀寫文件1.8 文件示例2 文件大小的計算1.9 文件示例3 擴展文件大小1.10 文件示例4 perror函數的使用1.11 阻塞與非阻塞的測試 2. 文…

關于「光學神經網絡」的一切:理論、應用與發展

/目錄/ 一、線性運算的光學實現 1.1. 光學矩陣乘法器 1.2. 光的衍射實現線性運行 1.3. 基于Rayleigh-Sommerfeld方程的實現方法 1.4. 基于傅立葉變換的實現 1.5. 通過光干涉實現線性操作 1.6. 光的散射實現線性運行 1.7. 波分復用&#xff08;WDM&#xff09;實現線性運…

Educoder中MATLAB數值計算與符號計算

第1關&#xff1a;數據處理 a[20 5 7 19 23 14 25 67 23 12]; %%%%%%%%% Begin %%%%%%%% smaxmax(a); sminmin(a); smeanmean(a); smedianmedian(a); ssumsum(a); %%%%%%%%% End %%%%%%%%% m[smax;smin;smean;smedian;ssum]; disp(m); 第2關&#xff1a;多項式計算與數值微積…

脈沖幅度調制信號的功率譜計算

本篇文章是博主在通信等領域學習時&#xff0c;用于個人學習、研究或者欣賞使用&#xff0c;并基于博主對人工智能等領域的一些理解而記錄的學習摘錄和筆記&#xff0c;若有不當和侵權之處&#xff0c;指出后將會立即改正&#xff0c;還望諒解。文章分類在通信領域筆記&#xf…

風口下的危與機:如何抓住生成式AI黃金發展期?

回顧AI的發展歷程&#xff0c;我們見證過幾次重大突破&#xff0c;比如2012年ImageNet大賽的圖像識別&#xff0c;2016年AlphaGo與李世石的圍棋對決&#xff0c;這些進展都為AI的普及應用鋪設了道路。而ChatGPT的出現&#xff0c;真正讓AI作為一個通用的產品&#xff0c;走入大…

Linux | 創建 | 刪除 | 查看 | 基本命名詳解

Linux | 創建 | 刪除 | 查看 | 基本命名詳解 文章目錄 Linux | 創建 | 刪除 | 查看 | 基本命名詳解前言一、安裝Linux1.1 方法一&#xff1a;云服務器方式1.2 方法二&#xff1a;虛擬機方式 二、ls2.2 ll 三、which3.1 ls -ld 四、pwd五、cd5.1 cd .\.5.2 ls -al5.3 重新認識命…

程序員兼職需要收藏的防坑技巧

不管你是剛剛上車的新職員&#xff0c;還是職場經營多年的老手&#xff0c;在零散時間&#xff0c;通過兼職搞一點零花錢&#xff0c;充實一下自己的生活&#xff0c;這是在正常不過的事情&#xff0c;但是很多同學害怕兼職有風險&#xff0c;被騙或者說找不到門路&#xff0c;…

優思學院|質量工程師在汽車行業待遇好嗎?

優思學院認為質量工程師在汽車行業的待遇有可能相對較好的。隨著中國汽車品牌在國內市場的崛起&#xff0c;特別是在電動汽車領域的增長&#xff0c;質量工程師在保障產品質量和安全性方面變得非常重要。由于中國汽車制造商對產品質量的高度重視&#xff0c;質量工程師在制定和…

AC自動機(簡單模板)

AC自動機&#xff0c;就相當于是在字典樹上用kmp。next數組回退的位置為最大匹配字符串在字典樹上的節點位置。 在獲取字典樹上的next數組的時候用的是BFS每次相當與處理的一層。 下圖中紅線為&#xff0c;可以回退的位置&#xff0c;沒有紅線的節點回退的位置都是虛擬原點。…

基于C#實現線段樹

一、線段樹 線段樹又稱"區間樹”&#xff0c;在每個節點上保存一個區間&#xff0c;當然區間的劃分采用折半的思想&#xff0c;葉子節點只保存一個值&#xff0c;也叫單元節點&#xff0c;所以最終的構造就是一個平衡的二叉樹&#xff0c;擁有 CURD 的 O(lgN)的時間。 從…

關于同一接口有多個不同實現的設計方案

關于同一接口有多個不同實現的設計方案 前言 最近公司做了一個銀行相關的項目&#xff0c;告訴我公司對接了多個銀行的支付&#xff0c;每個銀行都有對應的接口要去對接&#xff0c;比如&#xff1a;交易申請&#xff0c;交易取消&#xff0c;支付&#xff0c;回單&#xff0…

rabbitMQ發布確認-交換機不存在或者無法抵達隊列的緩存處理

rabbitMQ在發送消息時&#xff0c;會出現交換機不存在&#xff08;交換機名字寫錯等消息&#xff09;&#xff0c;這種情況如何會退給生產者重新處理&#xff1f;【交換機層】 生產者發送消息時&#xff0c;消息未送達到指定的隊列&#xff0c;如何消息回退&#xff1f; 核心&…

麒麟KYSEC使用方法05-命令設置密碼強度

原文鏈接&#xff1a;麒麟KYSEC使用方法05-命令設置密碼強度 hello&#xff0c;大家好啊&#xff0c;今天給大家帶來麒麟KYLINOS的kysec使用方法系列文章第五篇內容----使用命令設置密碼強度&#xff0c;密碼強度策略有兩個文件需要修改&#xff0c;pwquality.conf/login.defs&…

命令執行總結

之前做了一大堆的題目 都沒有進行總結 現在來總結一下命令執行 我遇到的內容 這里我打算按照過濾進行總結 依據我做過的題目 過濾system 下面是一些常見的命令執行內容 system() passthru() exec() shell_exec() popen() proc_open() pcntl_exec() 反引號 同shell_exec() …

大語言模型概述(三):基于亞馬遜云科技的研究分析與實踐

上期介紹了基于亞馬遜云科技的大語言模型相關研究方向&#xff0c;以及大語言模型的訓練和構建優化。本期將介紹大語言模型訓練在亞馬遜云科技上的最佳實踐。 大語言模型訓練在亞馬遜云科技上的最佳實踐 本章節內容&#xff0c;將重點關注大語言模型在亞馬遜云科技上的最佳訓…

解決Chrome瀏覽器無法啟動,因為應用程序的并行配置不正確

目錄 現象 方法1 方法2 附帶&#xff1a;書簽路徑 一次比較奇怪的問題&#xff0c;花了一些時間&#xff0c;記錄下來。 現象 進到本機默認安裝路徑&#xff1a; C:\Users\你的用戶名\AppData\Local\Google\Chrome\Application 下面會有個版本號的目錄&#xff0c;如我的…

跨地區企業組網方案對比與推薦

跨地區的企業&#xff0c;需要在不同的辦公室之間實現內部通信來進行業務協作。然而&#xff0c;在不同的地方建立局域網并將它們連接起來是一個棘手的問題。傳統的企業組網方案可能會面臨各種挑戰&#xff0c;包括網絡延遲、數據安全性、維護困難等等。 常見的組網方案有&…

快手ConnectionError

因為運行的程序被中斷導致 top然后查看站用處內存高的accelerate kill進程號 9回車

linux基礎5:linux進程1(馮諾依曼體系結構+os管理+進程狀態1)

馮諾依曼體系結構os管理 一.馮諾依曼體系結構&#xff1a;1.簡單介紹&#xff08;準備一&#xff09;2.場景&#xff1a;1.程序的運行&#xff1a;2.登錄qq發送消息&#xff1a; 3.為什么需要內存&#xff1a;1.簡單的引入&#xff1a;2.計算機存儲體系&#xff1a;3.內存的意義…