【Java】多線程Thread類

1. 進程與線程

進程與線程的基本認識

進程(Process):進程是程序的一次動態執行過程,它經歷了從代碼加載、執行、到執行完畢的一個完整過程;同時也是并發執行的程序在執行過程中分配和管理資源的基本單位,競爭計算機系統資源的基本單位。

線程(Thread):線程可以理解為進程中的執行的一段程序片段,是進程的一個執行單元,是進程內可調度實體,是比進程更小的獨立運行的基本單位,線程也被稱為輕量級進程。

即使多進程可以提高硬件資源的利用率,但是進程的啟動和銷毀需要消耗大量的系統性能,從而導致程序的執行性能下降。所以為了進一步提升并發操作的處理能力,在進程的基礎上又劃分了多線程概念。

2. 多線程實現

Thread類實現多線程

?Thread類的方法

1.通過繼承Thread類,并重寫父類的run()方法實現
public void run(){ }

定義線程類:


class MyThread extends Thread{@Overridepublic void run() {while(true){System.out.println("hello Thread");try{Thread.sleep(1000);}catch(InterruptedException e){throw new RuntimeException(e);}}}
}
public class Demo1 {public static void main(String[] args)throws InterruptedException {Thread t=new MyThread();t.start();//創建一個線程//t.run();while(true){System.out.println("hello main");Thread.sleep(1000);}//兩個循環在同時進行}
}

Runnable接口實現多線程

使用Thread類的確可以實現多線程,但是也容易發現它的缺陷:面向對象的單繼承局限,因此才采用Runnable接口來實現多線程。

該接口的定義如下(以下并不需要在代碼中實現):


class MyRunnable implements Runnable{@Overridepublic void run(){while(true){System.out.println("hello main");try{Thread.sleep(1000);}catch(InterruptedException e){throw new RuntimeException(e);}}}
}
public class Demo2 {public static void main(String[] args)throws Exception{Runnable runnable=new MyRunnable();Thread t=new Thread(runnable);t.start();while(true){System.out.println("hello main");Thread.sleep(1000);}}
}

Thread(String name)后邊兩種方法,我們可以給線程對象命名。

默認情況下,線程對象名字是Thread-N,N是從0開始增加。

3.Thread常見方法

start()

start() 啟動一個線程。

start()方法可以開啟一個線程,線程創建好后是不會開始執行的,要使用start來開啟。

只有當start(),操作系統內核才會創建一個真真正正的線程PCB,然后去調用run()方法,此時操作系統層面才會真的創建一個線程。

sleep()

使用sleep時會有一個中斷異常(非受查異常),需要我們手動拋出

join()

join(): 等待一個線程;

join(t)表示等待一個線程t毫秒。
因為我們線程是隨即調度的過程,線程的執行順便我們無法把控,但在一些場景下我們需要有明確的線程程序順序,等待線程,就是可以控制兩個線程的結束順序。

比如在main方法中有兩個線程t1、t2,在主線程中有t1.join() ,那么主線程就要阻塞 等待t1線程執行完了才能在執行。如果在t1線程中有t2.join(),那么t1線程就要阻塞 等待t2線程執行完了才能執行任務。

如果去掉join()方法后,主線程與Thread線程搶占式執行!


public class Demo12 {public static void main(String[] args)throws Exception {Thread t=new Thread(()->{for(int i=0;i<3000;i++){System.out.println("hello thread");try{Thread.sleep(1000);}catch(InterruptedException e) {throw new RuntimeException(e);}}System.out.println("線程結束");});t.start();t.join(3000);//等待線程t執行完畢System.out.println("main 線程結束");}
}

中斷線程

線程中斷: 我們這里的中斷,并不是線程立即就結束了,而是通知該線程,你應該結束了,但實際是否結束,取決于線程里具體的代碼

package Thread;public class Demo3 {public static  boolean flag=true;public static void main(String[] args)throws InterruptedException{Thread t1=new Thread(()->{while(flag){System.out.println("hello Thread");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}});t1.start();Thread.sleep(3000);flag=false;}
}

flag 變量的作用是作為線程執行的控制開關,用于安全地終止 t1 線程的循環執行。

flag?變量是主線程與?t1?線程之間的一個通信媒介,通過修改它的值,主線程可以安全地通知?t1?線程“該停止工作了”,避免了線程的無限循環。如果沒有?flagt1?線程的?while(true)?循環將無法終止,導致線程永久運行

即使?t1?線程因?sleep?進入阻塞狀態,只要?sleep?時間結束,線程恢復運行后會立即檢查?flag,從而響應終止信號。

4.Thread類的常見屬性

getId():

?ID是線程的唯一標識,不同的線程不重復

package Thread;class MyThread1 extends Thread{@Overridepublic void run(){System.out.println("hello word");}
}
public class getIdtest {public static void main(String[] args) {Thread t=new MyThread1();System.out.println(t.getId());}
}

getName:?

名稱是我們構造方法設置的名稱,如果沒有設置,那就是默認名。

public class getNametest {public static void main(String[] args) {Thread t=new Thread();System.out.println(t.getName());//因為我們沒有命名,所以使用的是默認名。}
}

getState():?

狀態:

getState()方法可以獲取當前Thread對象的狀態,這是Java層面定義的線程狀態,要注意和PCB上的區分。

線程有6種狀態:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING,? TERMINATED。

NEW表示創建好了一個Java線程對象,安排好了任務,只是還沒有啟動,沒有調用start方法之前是不會創建PCB的,和PCB沒有關系。

RUNNABLE是運行狀態或就緒狀態,在操作系統層面已經有了對應的PCB。

BLOCKED是阻塞狀態的一種,在等待鎖

WAITING表示一直沒有時間限制的等待,一直等直到被喚醒。

TIMED_WAITING指定了等待時間的阻塞狀態,過時就繼續執行任務。

TERMINATED是執行結束,PCB已經銷毀,Java層面的線程對象還在。

查看Thread對象的所有狀態:

package Thread;public class Demo14 {public static void main(String[] args) {for(Thread.State state: Thread.State.values()){System.out.println(state);}}
}

getPriority:?

可以獲取當前線程的優先級,但沒有太大的用,實際還得取決于操作系統內核的具體調度。

package Thread;public class test {public static void main(String[] args) {Thread t=new Thread();System.out.println(t.getPriority());}
}

isDaemon():?

是否為守護線程(也叫后臺線程), 簡單的理解一下,我們手動創建的線程都是前臺線程,JVM自帶的線程都是后臺線程,我們也可以通過setDaemon()方法將前臺線程設置為后臺線程。

 public static void main(String[] args) {Thread t=new MyThread2();System.out.println(t.isDaemon());}

isAlive():?

線程的run方法是否執行結束。

package Thread;
class MyThread2 extends Thread{@Overridepublic void run(){System.out.println("hello thread1");}
}
public class Demo4 {public static void main(String[] args) {Thread t=new MyThread2();System.out.println(t.isAlive());t.start();System.out.println(t.isAlive());}}

interrupt()方法

第一種解釋:

  1. 發送信號:通知線程“需要中斷當前操作”,而非強制殺死線程。
  2. 打破阻塞:中斷?sleep/wait?等阻塞方法,讓線程從阻塞中喚醒并處理中斷。
  3. 協作終止:線程通過檢查中斷狀態(isInterrupted())或處理?InterruptedException,決定是否結束,體現“誰運行誰控制”的設計原則

在?Demo3?中,正是由于?t1?線程內部通過?while (!isInterrupted())?主動響應中斷信號,主線程的?t1.interrupt()?才能安全、優雅地終止線程。

 public static void main(String[] args)throws InterruptedException{Thread t1=new Thread(()->{while(!Thread.currentThread().isInterrupted()){System.out.println("hello Thread");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}});t1.start();Thread.sleep(3000);t1.interrupt();}

第二個解釋:

1.把線程內部的標志位設置為true
2.如果線程正在sleep,會觸發異常,將sleep喚醒。
sleep喚醒的同時,會清空標志位,將剛才設置的標志位在設置為false(這就導致,我們的循環會繼續執行).
如果我們想去中斷,我們可以在異常里加一個break。

2.3 多線程運行狀態

任意線程具有5種基本的狀態:

1.創建狀態

實現Runnable接口和繼承Thread類創建一個線程對象后,該線程對象處于創建狀態,此時它已經有了內存空間和其它資源,但他還是處于不可運行的。

2.就緒狀態

新建線程對象后,調用該線程的start方法啟動該線程。啟動后,進入線程隊列排隊,由CPU調度服務。

3.運行狀態

就緒狀態的線程獲得處理器的資源時,線程就進入了運行狀態,此時將自動調用run方法。

4.阻塞狀態

正在運行的線程在某些特殊情況下,如:當前線程調用sleep、suspend、wait等方法時,運行在當前線程里的其它線程調用join方法時,以及等待用戶輸入的時候。只有當引起阻塞原因消失后,線程才能進入就緒狀態。

5.終止狀態

當線程run方法運行結束后,或者主線程的main()方法結束后,線程才能處于終止狀態,線程一旦死亡就不能復生。

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

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

相關文章

C/C++復習(四)

一.模版 模版涉及的是泛型編程&#xff0c;即通過編譯器去確定類型的編程方式&#xff0c;模版分為&#xff1a;類模板和函數模版&#xff0c;下面我們一一復習&#xff1a; 函數模版&#xff1a; 格式&#xff1a; template<typename T1, typename T2,......,typename Tn&g…

022 基礎 IO —— 文件

&#x1f984; 個人主頁: 小米里的大麥-CSDN博客 &#x1f38f; 所屬專欄: Linux_小米里的大麥的博客-CSDN博客 &#x1f381; GitHub主頁: 小米里的大麥的 GitHub ?? 操作環境: Visual Studio 2022 文章目錄基礎 IO —— C 語言文件 I/O 操作基礎前言1. C 語言文件操作函數匯…

MNN LLM Chat iOS 流式輸出優化實踐

本文介紹了在 iOS 平臺上使用 MNN 框架部署大語言模型&#xff08;LLM&#xff09;時&#xff0c;針對聊天應用中文字流式輸出卡頓問題的優化實踐。通過分析模型輸出與 UI 更新不匹配、頻繁刷新導致性能瓶頸以及缺乏視覺動畫等問題&#xff0c;作者提出了一套包含智能流緩沖、U…

【開發技巧】VS2022+QT5+OpenCV4.10開發環境搭建QT Creator

VS2022編譯器支持配置 QT5默認安裝以后支持的是VS2015與VS2017&#xff0c;不支持VS2022&#xff0c;所以必須首先在Qt Creator中配置支持VS2022。配置順序如下&#xff1a; 首先打開【工具】->【選項】 然點擊Kits里面的【編譯器】選項。點擊Manual下面的【C】然后點擊【…

【Linux系統】動靜態庫的制作

前言&#xff1a; 上文我們講到了文件系統【Linux系統】詳解Ext2&#xff0c;文件系統-CSDN博客 本文我們來講講動靜態庫的制作 庫 【Linux】編譯器gcc/g及其庫的詳細介紹_linux gcc 有哪些庫-CSDN博客 這篇文章的第4大點&#xff0c;簡單是介紹了一下庫的基本概念。 靜態庫 靜…

鏈式二叉樹的基本操作——遍歷

本文筆者將帶領讀者一起學習鏈式二叉樹的一些基本語法&#xff0c;至于更難一些的插入刪除等&#xff0c;筆者將在后續C更新后再次詳細帶領大家學習。 首先&#xff0c;在進行二叉樹之前&#xff0c;我們需要一顆二叉樹&#xff0c;而二叉樹的初始化現階段實現不太現實&#x…

Windows運維之以一種訪問權限不允許的方式做了一個訪問套接字的嘗試

一、問題場景 在Windows 上運維服務過程中&#xff0c;經常會遇到運行服務&#xff0c;部署安裝時候無任何問題&#xff0c;后續再某個特殊時間點&#xff0c;突然服務無法啟動了。再次啟動時&#xff0c;提示端口占用與以一種訪問權限不允許的方式做了一個訪問套接字的嘗試。 …

2020/12 JLPT聽力原文 問題二 3番

3番&#xff1a;レストランで、女の人と店長が話しています。店長はサラダについて、どんなアドバイスをしていますか。女&#xff1a;店長、この前話してた新しいランチメニューのサラダを作ってみたんですが、どうでしょうか。 男&#xff1a;ああ、サラダだけで満足できるっ…

芯片行業主要廠商

作為一個小白&#xff0c;每次淘寶買芯片時看到相似的命名規則&#xff1a;“OPA、AD、LT、MAX”等等時&#xff0c;我不禁好奇這些芯片行業大廠有哪些&#xff0c;所以查了些資料&#xff1a; 1. 德州儀器&#xff08;Texas Instruments, TI&#xff09; 公司概況&#xff1…

【BLE系列-第四篇】從零剖析L2CAP:信道、Credit流控、指令詳解

目錄 引言 一、L2CAP主要功能 二、L2CAP幀格式及信道概念 2.1 邏輯鏈路是什么&#xff1f; 2.2 邏輯信道的作用 2.3 L2CAP幀格式介紹 三、L2CAP信令信道 3.1 信令信道幀格式說明 3.2 信令信道指令介紹 3.2.1 信令信道指令一覽表 3.2.2 Credit流控規則 引言 在BLE協…

CSS保持元素寬高比,固定元素寬高比

方法一&#xff1a; <div class"hcp-fixed-aspect-ratio-box">這里是正文內容 </div>.hcp-fixed-aspect-ratio-box {width: 50%;color: #FFFFFF;margin: 100px auto;background: #FF0000;/* 寬高比2:1&#xff0c;兼容性可能不太好 */aspect-ratio: 2 / …

數據分析小白訓練營:基于python編程語言的Numpy庫介紹(第三方庫)(上篇)

&#xff08;一&#xff09;Numpy庫的安裝安裝指定版本的Numpy庫&#xff0c;打開命令提示符&#xff0c;輸入下圖內容&#xff0c;只需要將1.25.5的版本修改成個人需要的版本&#xff0c;然后按下回車鍵&#xff0c;numpy庫就安裝在python中&#xff1a;指定版本numpy庫安裝可…

從 Windows 到 Linux 服務器的全自動部署教程(免密登錄 + 壓縮 + 上傳 + 啟動)

一、準備工作 1. 環境說明 本地開發環境&#xff1a;Windows 服務器&#xff08;需執行部署腳本&#xff09;目標服務器&#xff1a;Linux 服務器&#xff08;需安裝 node.js、pm2、unzip&#xff09;核心工具&#xff1a;7-Zip&#xff08;壓縮&#xff09;、OpenSSH&#x…

智能汽車領域研發,復用云原始開發范式?

汽車電子電氣架構演進趨勢&#xff1a;分散的功能ECU -> 域控制器 -> 中央計算服務器汽車電子方案與架構在發展與迭代時會使用虛擬化方法幾種可行的軟硬一體化方案&#xff1a;多ECU&#xff0c;硬件隔離&#xff0c;硬件分區&#xff0c;車規級多核硬件架構 Hypervisor…

數據電臺詢價的詢價要求

技術規格及主要參數 1.電臺基本要求&#xff1a; 1.1 電臺中的信號處理基于FPGA設計&#xff0c;采用FPGAARM高速AD/DA設計架構&#xff1b; 1.2 具備頻譜感知、自主選頻、跳頻、擴頻等功能&#xff1b; 1.3 具備鏈路質量信息、自組網路由信息、電池電壓監測信息、北斗定位信息…

IoT/HCIP實驗-5/基于WIFI的智慧農業實驗(LwM2M/CoAP+PSK+ESP8266 連接到 IoTDA)

文章目錄概述WIFI8266 通信模組WIFI模組也用AT指令&#xff1f;ESP8266 內置協議棧?支持的無線網絡模式MCU通過串口與模組交互Wifi模組做客戶端PC-AT接入路由器向本地TCP服務發數據用代碼接入你家路由器已接入AP&#xff08;你家Wifi&#xff09;平臺側開發工程配置和編譯工程…

定時器輸出PWM波配置(呼吸燈)

使用定時器 4 通道 3 生成 PWM 波控制 LED1 &#xff0c;實現呼吸燈效果。 頻率&#xff1a;2kHz&#xff0c;PSC71&#xff0c;ARR499pwm.c:#include "pwm.h" // 本模塊頭文件&#xff1a;應聲明 pwm_init/pwm_compare_set 等原型、并包含 HAL 頭//&#xff08;示…

[ai-agent]環境簡介之沙盒e2b vs daytona

所謂的環境的就是agent運行在哪里&#xff0c;或者是agent和那里進行交互。 最常見的環境就是本地開發環境&#xff0c;也就是個人主機&#xff0c;但是存在問題就是沒有辦法出網和橫向擴展。 在沙盒之前也是有其他選擇的&#xff1a; 云服務器&#xff0c; 虛擬機&#xff0c;…

【前端面試題】前端面試知識點(第三十一題到第六十一題)

三十一. CSS實現垂直水平居中 實現元素的垂直水平居中是前端開發中的常見需求,主要有以下幾種思路: text-align + line-height實現單行文本水平垂直居中 適用于單行文本元素,通過text-align: center實現水平居中,line-height等于容器高度實現垂直居中 text-align + vertic…

嵌入式練習項目——————抓包獲取天氣信息

一、內容 嘗試通過實時天氣接口 - 數據接口 - NowAPI此網站獲取天氣信息&#xff0c;實現可以發送城市查詢當前天氣和未來天氣 二、獲取請求報文 可以根據測試示例看到獲取內容&#xff0c;此時數據是cJSON格式&#xff0c;我們首先要通過合適的網址抓包獲取到請求報文&#x…