做網(wǎng)站有用沒網(wǎng)絡營銷方案設計畢業(yè)設計
目錄
一.并發(fā)編程相關概念
線程與進程
多線程
Java中線程的狀態(tài)
二.線程的創(chuàng)建方法
方法一:繼承Thread類
方法二:實現(xiàn)Runnable接口
其他方法
三.Thread類詳解
Thread常見構造方法
Thread常見屬性
Thread常見方法
start() 與 run()?
sleep() 與 yield()?
join()?
inerrupt()?
一.并發(fā)編程相關概念
線程與進程
線程是程序的執(zhí)行流程的最小單元。一個進程(程序的執(zhí)行實例)可以由一個或多個線程組成,每個線程都有自己的執(zhí)行路徑和執(zhí)行狀態(tài)。線程可以并發(fā)執(zhí)行,即多個線程可以同時在不同的處理器核心或計算機上運行,從而提高程序的運行效率。
線程與進程的區(qū)別在于,進程是操作系統(tǒng)對一個正在運行的程序的抽象,而線程是進程內(nèi)部的一個執(zhí)行單位。一個進程可以有多個線程,這些線程共享進程的資源,如內(nèi)存空間、文件描述符等。線程之間可以通過共享內(nèi)存的方式進行通信,相比于進程間通信(如管道、消息隊列)的開銷更小。
多線程
對于多線程,我們可以舉出這樣的一個例子來幫助我們理解
一家公司要去銀行辦理業(yè)務,既要進行財務轉(zhuǎn)賬,又要進行福利發(fā)放,還得進行繳納社保。 如果只有張三一個會計就會忙不過來,耗費的時間特別長。為了讓業(yè)務更快的辦理好,張三又找 來兩位同事李四、王五一起來幫助他,三個人分別負責一個事情,分別申請一個號碼進行排隊, 自此就有了三個執(zhí)行流共同完成任務,但本質(zhì)上他們都是為了辦理一家公司的業(yè)務。 此時,我們就把這種情況稱為多線程,將一個大任務分解成不同小任務,交給不同執(zhí)行流就分別 排隊執(zhí)行。
?對于這樣的業(yè)務場景,張三、李四和王五各自都相對于一個線程,多個線程之間相互配合才促使了整體業(yè)務流程的順利進行,由此可見多線程對于任務處理的高效。其中由于李四、王五都是張三叫來的,所以張三一般被稱為主線程(Main Thread),李四和王五則為其他線程。
Java中線程的狀態(tài)
Java中線程的狀態(tài)有以下幾種:
1. 新建(New):線程被創(chuàng)建但還沒有開始執(zhí)行。
2. 就緒(Runnable):線程被調(diào)度并準備開始執(zhí)行,但還沒有獲取CPU執(zhí)行權。
3. 運行(Running):線程正在執(zhí)行任務。
4. 阻塞(Blocked):當線程執(zhí)行到某個阻塞操作時,如等待IO操作完成或等待某個鎖的釋放時,線程會進入阻塞狀態(tài)。
5. 等待(Waiting):線程執(zhí)行了Object類的wait()方法,或者Thread類的join()方法時,線程會進入等待狀態(tài)。
6. 超時等待(Timed Waiting):線程執(zhí)行了Thread類的sleep()方法或等待超時后,線程會進入超時等待狀態(tài)。
7. 終止(Terminated):線程執(zhí)行完任務后或者出現(xiàn)異常終止時,線程進入終止狀態(tài)。
二.線程的創(chuàng)建方法
線程是操作系統(tǒng)中的概念,操作系統(tǒng)內(nèi)核實現(xiàn)了線程這樣的機制,并且對用戶層提供了一些 API 供用戶使用(例如 Linux 的 pthread 庫)
而Java標準庫中 Thread 類,便可以視為是對操作系統(tǒng)提供的 API 進行了進一步的抽象和封裝,作為Java程序員就可以利用Thread 類來實現(xiàn)并發(fā)編程。
并發(fā)編程是指在計算機系統(tǒng)中,多個獨立的任務同時進行,每個任務由一個或多個線程執(zhí)行,并且這些線程可能在同一時刻同時運行。并發(fā)編程可以提高系統(tǒng)的執(zhí)行效率和資源利用率。在并發(fā)編程中,多個線程可以同時進行不同的操作,比如讀寫數(shù)據(jù)、計算、網(wǎng)絡通信等,它們可以同時執(zhí)行,不需要等待其他線程的完成。常見的并發(fā)編程模型有多線程、異步編程、并行計算等。
說了這么多,歸根結底還得落實到代碼上,我們常見的創(chuàng)建線程的方式有倆種。
方法一:繼承Thread類
- 創(chuàng)建一個繼承自Thread類的子類。
- 在子類中重寫run()方法,定義線程的執(zhí)行邏輯。
- 在主線程中創(chuàng)建子類對象,并調(diào)用start()方法啟動線程。
public class MyThread extends Thread {public void run() {// 線程執(zhí)行邏輯}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}
方法二:實現(xiàn)Runnable接口
- 創(chuàng)建一個實現(xiàn)了Runnable接口的類,并實現(xiàn)接口中的run()方法,定義線程的執(zhí)行邏輯。
- 在主線程中創(chuàng)建Runnable實例,并將其作為參數(shù)傳遞給Thread類的構造方法。
- 調(diào)用Thread對象的start()方法啟動線程。
public class MyRunnable implements Runnable {public void run() {// 線程執(zhí)行邏輯}public static void main(String[] args) {MyRunnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start();}
}
無論是繼承Thread類還是實現(xiàn)Runnable接口,都可以創(chuàng)建多個線程并同時運行,以實現(xiàn)并發(fā)執(zhí)行的效果。
其他方法
除此之外,使用匿名內(nèi)部類或lambda表達式可以更快速的創(chuàng)建線程
匿名內(nèi)部類創(chuàng)建Thread 子類對象
// 使用匿名類創(chuàng)建 Thread 子類對象
Thread t1 = new Thread() {@Overridepublic void run() {System.out.println("使用匿名類創(chuàng)建 Thread 子類對象");}
};
匿名內(nèi)部類創(chuàng)建 Runnable 子類對象
// 使用匿名類創(chuàng)建 Runnable 子類對象
Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("使用匿名類創(chuàng)建 Runnable 子類對象");}
});
?lambda 表達式創(chuàng)建Runnable 子類對象
// 使用 lambda 表達式創(chuàng)建 Runnable 子類對象
Thread t3 = new Thread(() -> System.out.println("使用匿名類創(chuàng)建 Thread 子類對象"));
Thread t4 = new Thread(() -> {System.out.println("使用匿名類創(chuàng)建 Thread 子類對象");
});
三.Thread類詳解
不管是上述創(chuàng)建線程中的哪一種方法,歸根結底都是由 Thread 類延申開來的,Thread 類是 JVM 用來管理線程的一個類,換句話說,每個線程都有一個唯一的 Thread 對象與之關聯(lián)。而 Thread 類的對象就是用來描述一個線程執(zhí)行流的,JVM 會將這些 Thread 對象組織起來,用于線程調(diào)度,線程管理。
Thread常見構造方法
方法 | 說明 |
Thread() | 創(chuàng)建線程對象 |
Thread(Runnable target) | 使用Runnable對象創(chuàng)建線程對象 |
Thread(String name) | 創(chuàng)建線程對象,并命名 |
Thread(Runnable target, String name) | 使用Runnable對象創(chuàng)建線程對象,并命名 |
Thread(ThreadGroup group, Runnable target) | 線程可以被用來分組管理,分好的組即為線程組 |
Thread常見屬性
屬性 | 獲取方法 |
ID | getId() |
名稱 | getName() |
狀態(tài) | getState() |
優(yōu)先級 | getPriority() |
是否后臺線程 | isDaemon() |
是否存活 | isAlive() |
是否被中斷 | isInterrupted() |
其中?ID 是線程的唯一標識,不同線程不會重復,優(yōu)先級高的線程理論上來說更容易被調(diào)度到,是否存活,簡單的理解的話就是?run 方法是否運行結束了
Thread常見方法
start() 與 run()?
- start()方法是Thread類中的一個方法,用于啟動一個新的線程。當調(diào)用start()方法時,系統(tǒng)會創(chuàng)建一個新的線程,并在新的線程中執(zhí)行run()方法的內(nèi)容。start()方法會在新的線程中執(zhí)行一些準備工作,然后調(diào)用run()方法。
- run()方法是實現(xiàn)了Runnable接口的類中的一個方法。在啟動一個線程后,系統(tǒng)會自動調(diào)用該線程對象的run()方法。run()方法中包含了線程的主體代碼,即線程要執(zhí)行的任務。
前文中我們已經(jīng)了解了如何通過重寫 run 方法創(chuàng)建一個線程對象,但線程對象被創(chuàng)建出來并不意味著線程就開始運行了。重寫 run 方法是提供給線程要做的事情的指令清單,線程對象可以認為是把李四、王五叫過來了,而調(diào)用start() 方法,就是喊一聲:“行動起來!”,線程才真正獨立去執(zhí)行。
public class MyThread extends Thread {public void run() {// 線程執(zhí)行邏輯}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}
就拿上面這段代碼來說,我們能不能不管start方法直接調(diào)用線程的run方法呢?
其實是可以調(diào)用run方法的,但是直接調(diào)用run方法只會在當前線程中運行run方法的代碼,不會啟動新的線程去執(zhí)行run方法。
而調(diào)用start方法則會啟動一個新的線程,然后在新的線程中執(zhí)行run方法的代碼。所以,如果只調(diào)用run方法而不調(diào)用start方法,則不會創(chuàng)建新的線程,無法實現(xiàn)多線程的并發(fā)執(zhí)行。
也就是說,我們可以這樣做,但是這樣做的話就不會實現(xiàn)多線程,始終我們都只能在一個線程中運行。因此在實際開發(fā)中,并不建議這樣做。?
還有一點需要注意的是,對于start方法,我們只能調(diào)用一次,不能重復調(diào)用,不然會報非法線程狀態(tài)異常,因為在調(diào)用start方法后,線程就已經(jīng)處于Runnable狀態(tài),對于已經(jīng)是Runnable狀態(tài)的線程,再讓它start為Runnable狀態(tài)顯然是不合理的。
sleep() 與 yield()?
在多線程編程中,可以使用sleep和yield方法來控制線程的執(zhí)行。
- sleep方法:sleep方法是Thread類提供的靜態(tài)方法,可以使當前線程暫停一段時間,讓其他線程有機會執(zhí)行。調(diào)用sleep方法后,線程會進入阻塞狀態(tài),不會占用CPU資源。sleep方法的語法是:Thread.sleep(long millis),其中millis參數(shù)表示暫停的時間,以毫秒為單位。例如,Thread.sleep(100)表示暫停100毫秒。
- yield方法:yield方法是Thread類提供的靜態(tài)方法,可以使當前線程讓出CPU資源,使其他同優(yōu)先級的線程有機會執(zhí)行。調(diào)用yield方法后,線程會進入就緒狀態(tài),讓出CPU資源,但并不是完全放棄CPU資源,可能會立即重新獲取CPU資源。yield方法的語法是:Thread.yield()。例如,Thread.yield()表示當前線程讓出CPU資源,給其他同優(yōu)先級的線程執(zhí)行的機會。
總的來說,sleep方法是讓當前線程暫停一段時間,不會占用CPU資源,適合用于控制線程執(zhí)行的時間間隔。yield方法是讓當前線程主動讓出CPU資源,給其他同優(yōu)先級的線程執(zhí)行的機會,適合用于在多個線程之間平衡負載,提高系統(tǒng)的性能。
join()?
join()方法是Thread類的一個方法,它用于等待該線程完成執(zhí)行。具體而言,當調(diào)用一個線程的join()方法時,當前線程會被阻塞,直到該線程執(zhí)行完成。
join()方法有兩個重載版本:
- join():等待被調(diào)用線程執(zhí)行完成。
- join(long millis):等待被調(diào)用線程執(zhí)行完成,但最多等待millis毫秒。
下面是一個例子,演示如何使用join()方法等待線程執(zhí)行完成:
public class JoinExample {public static void main(String[] args) {Thread thread1 = new Thread(new MyRunnable(), "Thread 1");Thread thread2 = new Thread(new MyRunnable(), "Thread 2");thread1.start();thread2.start();try {thread1.join();thread2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("All threads have finished execution.");}
}class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " is executing.");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " has finished execution.");}
}
在上面的例子中,我們創(chuàng)建了兩個線程thread1和thread2,并將它們啟動。然后,我們使用join()方法等待這兩個線程執(zhí)行完成。最后,當兩個線程都執(zhí)行完成后,才會打印"All threads have finished execution."。
inerrupt()?
在Java中,線程的interrupt()方法用于中斷線程。當一個線程調(diào)用interrupt()方法時,如果目標線程當前正在執(zhí)行可中斷的操作(如sleep()、join()、wait()等),它將會收到一個InterruptedException異常,從而提前退出。
如果目標線程沒有在可中斷操作中阻塞,而是在運行中,那么調(diào)用interrupt()方法將設置目標線程的中斷標志位為true。這樣,目標線程可以通過檢查自己的中斷標志位來自行決定是否中斷執(zhí)行。
下面是一個示例:
public class MyThread extends Thread {public void run() {while (!Thread.currentThread().isInterrupted()) {// 執(zhí)行一些操作}System.out.println("線程被中斷");}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();}
}
在上述示例中,我們創(chuàng)建了一個繼承自Thread類的自定義線程MyThread。在run() 方法中,我們使用了一個循環(huán)來模擬線程的執(zhí)行操作。每次循環(huán)都會檢查中斷標志位,如果為true則退出循環(huán)并輸出"線程被中斷"。在前文的Thread類常見屬性也說過了使用 isInterrupted() 方法就可以獲取當前線程的中斷標志位。
備注:和 isInterrupted() 相似的還有一個方法叫做 interrupt() 二者都能判斷線程是否被打斷,但是不同的點在于前者只是做出判斷,并不會手動修改這個標記;而后者會在判斷后手動清除打斷標記,也就是置為false。
在main方法中,我們創(chuàng)建了一個MyThread對象并啟動線程。然后通過調(diào)用Thread.sleep() 方法來讓主線程睡眠1秒,最后調(diào)用thread.interrupt() 方法中斷線程。當調(diào)用interrupt() 方法時,MyThread線程在下一個循環(huán)迭代時會檢查到中斷標志位為true,從而退出了循環(huán)并輸出"線程被中斷"。
?本次的分享就到此為止了,希望我的分享能給您帶來幫助,創(chuàng)作不易也歡迎大家三連支持,你們的點贊就是博主更新最大的動力!
如有不同意見,歡迎評論區(qū)積極討論交流,讓我們一起學習進步!
有相關問題也可以私信博主,評論區(qū)和私信都會認真查看的,我們下次再見