多線程萬字詳解

進程線程是計算機程序執行的兩個重要概念。

1.進程: 進程是操作系統分配資源的基本單位,每個進程都有自己獨立的地址空間,每啟動一個進程,系統就會為它分配內存。進程間通信比較復雜,需要用到IPC(InterProcess Communication,進程間通信)機制。

進程有五種狀態:創建、就緒、運行、阻塞和終止。

2.線程: 線程是進程中的一個執行單元,一個進程可以包含多個線程,它們共享進程的地址空間和資源。線程間通信比進程間通信要簡單很多,因為它們可以直接讀寫進程數據段(如全局變量)來進行通信。

線程也有五種狀態:創建、就緒、運行、阻塞和終止。

3.進程和線程的區別

  • 獨立性:進程間的內存空間是獨立的,而線程共享進程的內存空間。

  • 資源消耗:創建或銷毀進程時,系統性能開銷明顯,而線程的資源消耗遠小于進程。

  • 通信方式:進程間通信需要使用IPC機制,而線程可以直接讀寫全局變量進行通信。

  • 影響:一個進程崩潰后,其他進程不受影響;而一個線程崩潰,會導致整個進程崩潰。

4.多線程和多進程的選擇: 在需要進行頻繁通信的情況下,多線程更有優勢,因為它們可以直接讀寫內存進行通信。而在需要大量計算且相互獨立的情況下,多進程可能更合適,因為它們不會因為一個進程的崩潰而影響其他進程。

并發和并行

并發:在同一時刻,有多個指令在單個CPU上交替執行。

并行:在同一時刻,有多個指令在多個CPU上同時執行。

實現多線程方式一:繼承Thread類

方法介紹
方法名說明
void run()在線程開啟后,此方法將被調用執行
void start()使此線程開始執行,Java虛擬機會調用run方法()

實現步驟

  • 定義一個類MyThread繼承Thread類

  • 在MyThread類中重寫run()方法

  • 創建MyThread類的對象

  • 啟動線程

  • 代碼演示

public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName()+"Hello World");}}
}
public class ThreadDemo {public static void main(String[] args) {/*多線程第一種啟動方式1.自己定義一個類繼承Thread2.重寫run方法3.創建子類的對象,并啟動線程*/MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("線程一");t2.setName("線程二");//開啟線程t1.start();}
}

?

實現多線程方式二:實現Runnable接口

Thread構造方法

方法名說明
Thread(Runnable target)分配一個新的Thread對象
Thread(Runnable target, String name)分配一個新的Thread對象

?

實現步驟

  • 定義一個類MyRunnable實現Runnable接口

  • 在MyRunnable類中重寫run()方法

  • 創建MyRunnable類的對象

  • 創建Thread類的對象,把MyRunnable對象作為構造方法的參數

  • 啟動線程

public class MyRun implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {//獲取到當前線程的對象Thread t = Thread.currentThread();System.out.println(t.getName()+"Hello World");}}
}
public class ThreadDemo {public static void main(String[] args) {/*多線程第二種啟動方式1.自己定義一個類繼承Runnable接口2.重寫run方法3.創建自己類的對象4.創建一個Thread類的對象,并開啟線程*///創建MyRun的對象//表示多線程要執行的任務MyRun mr = new MyRun();//創建線程對象Thread t1 = new Thread(mr);Thread t2 = new Thread(mr);t1.setName("線程一");t2.setName("線程二");//開啟線程t1.start();}
}

?

實現多線程方式三: 實現Callable接口

方法介紹

方法名說明
V call()計算結果,如果無法計算結果,則拋出一個異常
FutureTask(Callable<V> callable)創建一個 FutureTask,一旦運行就執行給定的 Callable
V get()如有必要,等待計算完成,然后獲取其結果

?

實現步驟

  • 定義一個類MyCallable實現Callable接口

  • 在MyCallable類中重寫call()方法

  • 創建MyCallable類的對象

  • 創建Future的實現類FutureTask對象,把MyCallable對象作為構造方法的參數

  • 創建Thread類的對象,把FutureTask對象作為構造方法的參數

  • 啟動線程

  • 再調用get方法,就可以獲取線程結束之后的結果。

代碼演示

public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 0; i <= 100; i++) {sum = sum + i;}return sum;}
}

?

public class ThreadDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {/*多線程的第三種實現方式特點:可以獲取到多線程運行到的結果1.創建一個類MyCallable實現Callable接口2.重寫call(有返回值,表示多線程運行的結果)3.創建MyCallable的對象(表示多線程要執行的任務)4.創建FutureTask的對象(作用管理多線程運行的結果)5.創建Thread類的對象,并啟動*/MyCallable mc = new MyCallable();FutureTask<Integer> ft = new FutureTask(mc);Thread thread = new Thread(ft);thread.start();//獲取多線程運行的結果Integer result = ft.get();System.out.println(result);}
}

?Java中多線程的三種主要實現方式各有其特點和適用場景。具體來說:

  • 繼承Thread類:通過繼承Thread類并重寫run方法來實現多線程,這種方法簡單直觀,但在Java的單繼承體系下,可能會導致類的擴展性受限。
  • 實現Runnable接口:通過實現Runnable接口并將該實現類的實例傳遞給Thread對象來創建線程,這種方式避免了單繼承的限制,提高了代碼的可讀性和可維護性。
  • 實現Callable接口:與Runnable類似,但可以返回執行結果,通常與FutureTask結合使用,允許線程執行完畢后獲取返回值,增加了線程的使用場景。

總的來說,如果需要簡單的線程邏輯并且不需要額外的返回結果,可以選擇繼承Thread類或實現Runnable接口。而當需要更復雜的線程管理和控制,或者希望利用線程池等高級特性時,應該考慮使用Executor框架。

線程休眠

相關方法

方法名說明
static void sleep(long millis)使當前正在執行的線程停留(暫停執行)指定的毫秒數

?代碼演示

public class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 100; i++) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "---" + i);}}
}
public class Demo {public static void main(String[] args) throws InterruptedException {/*System.out.println("睡覺前");Thread.sleep(3000);System.out.println("睡醒了");*/MyRunnable mr = new MyRunnable();Thread t1 = new Thread(mr);Thread t2 = new Thread(mr);t1.start();t2.start();}
}

線程優先級

線程調度

在Java中,除了上述兩種基本的調度方式,還可以通過編程手段對線程的執行順序進行一定程度的控制。例如,可以在需要等待或者后執行的線程中加入sleep()方法,使其在進入CPU調度初期就進入休眠狀態,從而給其他線程執行的機會。

優先級相關方法代碼演示

  • 線程調度是指在多線程環境中,操作系統或運行時環境如何分配CPU資源給各個線程的過程。

    線程調度主要有兩種調度方式:

  • 分時調度:這種調度方式下,CPU的時間被平均分配給所有線程。每個線程輪流獲得CPU的使用權,執行一段時間后再切換到下一個線程。這種方式簡單公平,但可能不是最高效的方式,因為它不考慮線程的優先級和實際需求。
  • 搶占式調度:這種調度方式會根據線程的優先級來決定哪個線程獲得CPU的使用權。優先級高的線程會得到更多的執行機會。如果多個線程的優先級相同,通常會隨機選擇一個線程來執行。Java使用的就是搶占式調度,這種方式能夠更好地滿足高優先級任務的需求。
方法名說明
final int getPriority()返回此線程的優先級
final void setPriority(int newPriority)更改此線程的優先級線程默認優先級是5;線程優先級的范圍是:1-10
public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "---" + i);}return "線程執行完畢了";}
}

?

public class Demo {public static void main(String[] args) {//優先級: 1 - 10 默認值:5MyCallable mc = new MyCallable();FutureTask<String> ft = new FutureTask<>(mc);Thread t1 = new Thread(ft);t1.setName("飛機");t1.setPriority(10);//System.out.println(t1.getPriority());//5t1.start();MyCallable mc2 = new MyCallable();FutureTask<String> ft2 = new FutureTask<>(mc2);Thread t2 = new Thread(ft2);t2.setName("坦克");t2.setPriority(1);//System.out.println(t2.getPriority());//5t2.start();}

守護線程

相關方法代碼演示

方法名說明
void setDaemon(boolean on)將此線程標記為守護線程,當運行的線程都是守護線程時,Java虛擬機將退出
public class MyThread1 extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(getName() + "---" + i);}}
}
public class MyThread2 extends Thread {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + "---" + i);}}
}
public class Demo {public static void main(String[] args) {MyThread1 t1 = new MyThread1();MyThread2 t2 = new MyThread2();t1.setName("女神");t2.setName("備胎");//把第二個線程設置為守護線程//當普通線程執行完之后,那么守護線程也沒有繼續運行下去的必要了.t2.setDaemon(true);t1.start();t2.start();}
}

線程的生命周期

線程同步

賣票

案例需求

電影院賣100張票,

而它有3個窗口賣票,請設計一個程序模擬該電影院賣票

實現步驟

public class SellTicket extends Thread {static int ticket = 0;@Overridepublic void run() {while (true) {if (ticket < 100) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}ticket++;System.out.println(getName() + "正在賣" + ticket + "票");} else {break;}}}
}
public class ThreadDemo {                       public static void main(String[] args) {/*某電影院目前正在上映國產大片,共有100張票,而它有3個窗口賣票,請設計一個程序模擬該電影院賣票*/SellTicket s1 = new SellTicket();SellTicket s2 = new SellTicket();SellTicket s3 = new SellTicket();s1.setName("窗口一");s2.setName("窗口二");s3.setName("窗口三");s1.start();s2.start();s3.start();}}

賣票案例的問題

  • 賣票出現了問題

    • 相同的票出現了多次

    • 出現了多的票

  • 問題產生原因

    線程執行的隨機性導致的,可能在賣票過程中丟失cpu的執行權,導致出現問題

同步代碼塊解決數據安全問題

  • 安全問題出現的條件

    • 是多線程環境

    • 有共享數據

    • 有多條語句操作共享數據

  • 如何解決多線程安全問題呢?

    • 基本思想:讓程序沒有安全問題的環境

  • 怎么實現呢?

    • 把多條語句操作共享數據的代碼給鎖起來,讓任意時刻只能有一個線程執行即可

    • Java提供了同步代碼塊的方式來解決

同步代碼塊格式:

synchronized(任意對象) { 多條語句操作共享數據的代碼 
}

synchronized(任意對象):就相當于給代碼加鎖了,任意對象就可以看成是一把鎖

同步的好處和弊端

  • 好處:解決了多線程的數據安全問題

  • 弊端:當線程很多時,因為每個線程都會去判斷同步上的鎖,這是很耗費資源的,無形中會降低程序的運行效率

代碼演示

public class SellTicket extends Thread {static int ticket = 0;//鎖對象,一定是唯一的@Overridepublic void run() {synchronized (SellTicket.class){while (true) {if (ticket < 100) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}ticket++;System.out.println(getName() + "正在賣" + ticket + "票");} else {break;}}}}
}

同步方法解決數據安全問題

同步方法的格式

同步方法:就是把synchronized關鍵字加到方法上

修飾符 static synchronized 返回值類型 方法名(方法參數) { 方法體;
}

同步靜態方法的鎖對象是什么呢?

類名.class

非靜態:this

同步靜態方法的鎖對象是當前類的Class對象

在Java中,當使用synchronized關鍵字修飾一個靜態方法時,這意味著這個方法被同步化,并且所有線程在訪問這個方法時必須先獲得鎖。對于靜態同步方法,這個鎖就是當前類的Class對象。這與其他非靜態同步方法使用的鎖不同,后者使用的是實例對象作為鎖。

具體來說,當一個線程嘗試訪問一個類的靜態同步方法時,它會嘗試獲取該類對應的Class對象的鎖。如果該鎖已被其他線程持有,則當前線程必須等待直到鎖被釋放。這種機制確保了同一時刻只有一個線程能夠執行同一個類的任何靜態同步方法。

此外,靜態同步方法與非靜態同步方法之間不會發生競態條件,因為它們使用的是不同的鎖對象。靜態同步方法使用的是類對象本身的鎖,而非靜態同步方法使用的是實例對象的鎖。

了解同步靜態方法的鎖對象對于編寫多線程程序和理解Java內存模型中的線程安全和并發控制非常重要。

Lock鎖

Lock鎖是Java并發編程中的一種同步機制,它提供了比synchronized關鍵字更加靈活的鎖操作

首先,Lock鎖的優勢在于它能夠提供更廣泛的鎖操作。與synchronized相比,Lock鎖可以實現更細粒度的鎖控制,例如可重入鎖、公平鎖等。具體來說:

  • 可重入鎖:允許同一個線程多次獲得鎖,而不會導致自己被阻塞。
  • 公平鎖:保證等待時間最長的線程能夠先獲得鎖,避免線程饑餓現象。
  • 讀寫鎖:允許多個讀線程同時訪問,但在寫線程訪問時會獨占鎖。

此外,Lock鎖的使用通常需要手動釋放,這要求開發者在finally塊中釋放鎖以確保資源的正確釋放。而synchronized則不需要手動釋放。

總的來說,Lock鎖提供了更多的功能和靈活性,但也帶來了更高的復雜性。在使用Lock鎖時,需要注意正確管理鎖的獲取和釋放,以避免死鎖或資源泄露。

Lock是接口不能直接實例化,這里采用它的實現類ReentrantLock來實例化

ReentrantLock構造方法

方法名說明
ReentrantLock()創建一個ReentrantLock的實例

加鎖解鎖方法

方法名說明
void lock()獲得鎖
void unlock()釋放鎖

代碼演示

  public class Ticket implements Runnable {//票的數量private int ticket = 100;private Object obj = new Object();private ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {//synchronized (obj){//多個線程必須使用同一把鎖.try {lock.lock();if (ticket <= 0) {//賣完了break;} else {Thread.sleep(100);ticket--;System.out.println(Thread.currentThread().getName() + "在賣票,還剩下" + ticket + "張票");}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}// }}}}

死鎖

死鎖是指兩個或多個執行單元(例如進程、線程或事務)在等待彼此持有的資源時,導致它們都無法 progress。產生死鎖的情況通常涉及以下四個方面:

  1. 互斥條件:指資源至少由一個執行單元持有,且在釋放之前其他執行單元無法使用。
  2. 占有和等待條件:指執行單元已經持有至少一個資源,但又提出了新的資源請求,被阻塞的執行單元仍然保持著它的資源。
  3. 不剝奪條件:指一個執行單元獲得的資源在未使用完之前不能被強行剝奪,即使該資源有可能滿足其他等待資源的執行單元的需求。
  4. 循環等待條件:存在一種環形鏈,每個執行單元都在等待下一個執行單元所占有的資源。

在實際開發中,為了避免死鎖,可以采取一些策略,如盡量減少事務的大小和持續時間,避免長時間占用鎖資源,以及盡量保持事務之間訪問資源的一致性和順序,避免交叉鎖定。

下面是可以產生死鎖的一段代碼:~

public class DeadlockDemo {private static Object lock1 = new Object();private static Object lock2 = new Object();public static void main(String[] args) {Thread thread1 = new Thread(() -> {synchronized (lock1) {System.out.println("Thread 1: Holding lock 1...");try {Thread.sleep(100); // 模擬耗時操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread 1: Waiting for lock 2...");synchronized (lock2) {System.out.println("Thread 1: Holding lock 1 & 2...");}}});Thread thread2 = new Thread(() -> {synchronized (lock2) {System.out.println("Thread 2: Holding lock 2...");try {Thread.sleep(100); // 模擬耗時操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread 2: Waiting for lock 1...");synchronized (lock1) {System.out.println("Thread 2: Holding lock 1 & 2...");}}});thread1.start();thread2.start();}
}

生產者消費者

概述

生產者消費者模式是一種經典的多線程協作模型,它涉及兩類線程:生產者和消費者。

生產者:負責生產數據或對象,并將它們放入一個共享的隊列中。生產者不直接與消費者交互,而是將產品放入隊列后繼續生產,這樣可以保證生產者的效率不會因為等待消費者而降低。 消費者:負責從隊列中取出數據或對象并進行消費。消費者不需要等待生產者生產,只需檢查隊列中是否有產品可消費。這樣,消費者可以保持持續的工作狀態,提高整體的處理效率。

此外,在實現生產者消費者模式時,通常需要考慮以下幾個關鍵點:

  • 共享隊列:生產者和消費者通過這個隊列進行間接通信。生產者將產品放入隊列,消費者從隊列中取出產品。
  • 同步機制:需要確保當隊列滿時,生產者停止生產;當隊列空時,消費者停止消費。這通常通過使用信號量、鎖或其他同步機制來實現。
  • 線程通信:在某些情況下,生產者生產了新的產品后,需要通知消費者來消費。這種通信可以通過條件變量或其他同步工具來實現。

總的來說,生產者消費者模式有效地解決了生產者和消費者之間的速度匹配問題,允許兩者以不同的速度運行,同時確保數據的安全傳輸和處理。

方法名說明
void wait()導致當前線程等待,直到另一個線程調用該對象的 notify()方法或 notifyAll()方法
void notify()喚醒正在等待對象監視器的單個線程
void notifyAll()喚醒正在等待對象監視器的所有線程

為方便理解采用以下示例

來源://https://www.bilibili.com/video/BV17F411T7Ao/

桌子

public class Desk {/*作用:控制生產者和消費者的執行*///是否有面條 0:沒有 1:有面條public static int foodFlag = 0;//總個數public static int count = 10;//鎖對象public static Object lock = new Object();}

生產者

public class Cook extends Thread{@Overridepublic void run() {while(true){synchronized (Desk.lock){if(Desk.count == 0){break;}else {//判斷桌子上是否有食物if(Desk.foodFlag == 1){//如果有,就等待try {Desk.lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}else {//如果沒有,就制作食物System.out.println("廚師做了一碗面條");//修改桌子上的食物狀態Desk.foodFlag = 1;//叫醒等待的消費者開吃Desk.lock.notifyAll();}}}}}
}

消費者

public class Foodie extends Thread{@Overridepublic void run() {while(true){synchronized (Desk.lock){if(Desk.count == 0){break;}else {if(Desk.foodFlag == 0){//用鎖的對象調用wait()try {//讓當前線程跟鎖進行綁定Desk.lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}else {Desk.count--;//如果有,就開吃System.out.println("吃貨正在吃面條,還能再吃"+Desk.count+"碗!!!");//吃完之后,喚醒廚師繼續做Desk.lock.notify();Desk.foodFlag = 0;}}}}}
}

二:阻塞隊列完成等待喚醒機制

生產者

public class Cook extends Thread{ArrayBlockingQueue<String> queue;public Cook(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while(true){//不斷的把面條放在阻塞隊列當中try {queue.put("面條");System.out.println("廚師放了一碗面條");} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class Foodie extends Thread{ArrayBlockingQueue<String> queue;public Foodie(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while(true){//不斷從阻塞隊列中獲取面條try {String food = queue.take();System.out.println(food);} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class ThreadDemo {public static void main(String[] args) {/*利用阻塞隊列完成生產者消費者(等待喚醒機制)//細節:生產者消費者必須使用同一個阻塞隊列*///1.創建阻塞隊列的對象ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);//創建線程的對象,并把阻塞隊列傳遞過去Cook c = new Cook(queue);Foodie f = new Foodie(queue);c.start();f.start();}
}

線程狀態

線程池

線程池是一種用于管理線程的資源池,它可以顯著提高多線程程序的性能和可靠性

線程池的實現基于生產者-消費者模式,任務提交方作為生產者將任務放入線程池,而線程池中的工作線程作為消費者來執行這些任務。以下是線程池的一些關鍵特點:

  1. 線程復用:線程池通過重用現有線程來執行新任務,減少了頻繁創建和銷毀線程所帶來的開銷。
  2. 任務管理:線程池內部通常有一個工作隊列,用于存儲等待執行的任務,這樣可以實現任務的有序執行。
  3. 性能提升:通過減少線程創建的開銷和優化線程調度,線程池能夠提高程序的響應速度和吞吐量。
  4. 資源控制:線程池可以限制同時運行的線程數量,防止系統過載,同時也可以減少上下文切換的開銷。
  5. 編程簡化:使用線程池可以簡化多線程編程,開發者只需關注任務的實現,而不必處理線程的創建和管理細節。
  6. 異步執行:線程池支持異步執行任務,可以在不阻塞主線程的情況下執行耗時操作,提升用戶體驗。
  7. 靈活性:現代編程語言如C++提供了豐富的API和庫來支持線程池的實現,使得開發者可以根據需要定制線程池的行為。
  8. 并發控制:線程池可以幫助開發者更好地控制并發級別,避免資源競爭和死鎖等問題。

綜上所述,線程池是一種高效的線程管理機制,它通過池化技術優化了線程的創建、管理和調度,為并發編程提供了強大支持。在實際應用中,合理地使用線程池可以帶來顯著的性能提升和更好的資源利用率。

線程池代碼實現

  1. 創建線程池

  2. 提交任務

  3. 所有的任務全部執行完畢,關閉線程池

線程池-Executors默認線程池

我們可以使用Executors中所提供的靜態方法來創建線程池

static ExecutorService newCachedThreadPool() 創建一個默認的線程池 ? static newFixedThreadPool(int nThreads) 創建一個指定最多線程數量的線程池

public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println(Thread.currentThread().getName()+"---"+ i);}}
}
public class test8 {public static void main(String[] args) {//獲取線程池對象ExecutorService pool1 = Executors.newCachedThreadPool();//ExecutorService pool1 = Executors.newCachedThreadPool(3);//提交任務pool1.submit(new MyRunnable());//銷毀線程池/* pool1.shutdown();*/}
}

線程池-參數詳解

Java中的線程池通過ThreadPoolExecutor類實現,它提供了靈活的參數配置來滿足不同場景的需求。以下是該類構造方法中的七個主要參數及其作用:

  1. corePoolSize:這是線程池的核心線程數量,即線程池中始終保持的最小線程數。即使這些線程處于空閑狀態,也不會被銷毀,除非設置了allowCoreThreadTimeOut屬性。
  2. maximumPoolSize:這是線程池允許創建的最大線程數量。當任務數量超過核心線程數時,線程池會嘗試創建新的線程來處理任務,但總數不會超過這個參數指定的值。
  3. keepAliveTime:當線程池中的線程數量超過核心線程數時,多余的空閑線程在被銷毀之前可以存活的時間。這個參數可以幫助控制資源使用,避免長時間持有不必要的線程資源。
  4. unit:與keepAliveTime參數配合使用,用于指定keepAliveTime的時間單位,如TimeUnit.SECONDS表示秒。
  5. workQueue:用于存放待執行任務的阻塞隊列。不同的隊列實現有不同的特性,如ArrayBlockingQueueLinkedBlockingQueue等,選擇合適的隊列對線程池的性能有重要影響。
  6. threadFactory:用于創建新線程的工廠。可以通過實現ThreadFactory接口來自定義線程的創建過程,如設置線程名稱、守護狀態等。
  7. handler:當線程池和隊列都滿了,無法接受新任務時的拒絕策略。常見的策略有AbortPolicy(默認,拋出異常)、CallerRunsPolicy(調用者運行)和DiscardOldestPolicy(丟棄最舊任務)等。

綜上所述,合理配置這些參數對于提高線程池的效率和穩定性至關重要。例如,根據任務的特性和系統的資源狀況來調整核心線程數和最大線程數,以及選擇適合的拒絕策略,可以在保證性能的同時避免資源的過度消耗

為方便理解看下圖 圖源://??黑馬程序員Java零基礎視頻教程_上部(Java入門,含斯坦福大學練習題+力扣算法題和大廠java面試題)_嗶哩嗶哩_bilibili

?

public class test8 {public static void main(String[] args) {ThreadPoolExecutor pool = new ThreadPoolExecutor(3,//核心線程數量,不能小于06,//最大線程數,不能小于0,最大數量 >= 核心線程數量60, //空閑線程最大存活時間TimeUnit.SECONDS,//時間單位new ArrayBlockingQueue<>(3),//任務隊列Executors.defaultThreadFactory(),Executors.defaultThreadFactory(),//創建線程工廠new ThreadPoolExecutor.AbortPolicy()//任務的拒絕策略);}
}

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

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

相關文章

js監聽F11觸發全屏事件

當用戶使用 F11 鍵進行瀏覽器全屏時&#xff0c;由于此時并非通過瀏覽器提供的 Fullscreen API 進入全屏模式&#xff0c;因此無法通過 fullscreenchange 事件來監聽全屏狀態的變化。在這種情況下&#xff0c;可以通過監聽 resize 事件來檢測瀏覽器窗口大小的變化&#xff0c;從…

【學習日記】快速排序

思想 快速排序之所以快&#xff0c;一個重要原因就是其每一次遍歷&#xff0c;都把本輪要排序的數字&#xff08;稱為軸&#xff09;放到了最終的位置上快排使用分治思想&#xff0c;所以一般采用遞歸實現&#xff0c;非遞歸版本可以用棧根據第一點&#xff0c;我們需要一個函…

[滲透教程]-006-滲透測試-Metasploit

文章目錄 1.Metasploit簡介2.配置2.1方法1 推薦2.2方法23.使用4. Metasploitable2-linuxMetasploit攻擊流程攻擊實例步驟會話管理1.Metasploit簡介 Metasploit是一個滲透測試平臺,使您能夠查找,利用和驗證漏洞.是一個免費的可下載的,通過它可以很容易對計算機軟件漏洞實施攻擊.…

AttributeError_ ‘list‘ object has no attribute ‘view‘

問題描述 訓練yolov9的時候遇到了下面的問題。 In loss_tal.py: pred_distri, pred_scores torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( (self.reg_max * 4, self.nc), 1) The error is as follows&#xff1a; AttributeError: list …

JavaWeb之 Web概述

目錄 前言1.1 Web和 JavaWeb的概念1.2 JavaWeb技術棧1.2.1 B/S架構1.2.2 靜態資源1.2.3 動態資源1.2.4 數據庫1.2.5 HTTP協議1.2.6 Web服務器 1.3 JavaWeb 學習內容 前言 博主將用 CSDN 記錄 Java 后端開發學習之路上的經驗&#xff0c;并將自己整理的編程經驗和知識分享出來&a…

【Web自動化測試——代碼篇十二】自動化測試模型——數據驅動測試和關鍵字驅動測試

&#x1f525; 交流討論&#xff1a;歡迎加入我們一起學習&#xff01; &#x1f525; 資源分享&#xff1a;耗時200小時精選的「軟件測試」資料包 &#x1f525; 教程推薦&#xff1a;火遍全網的《軟件測試》教程 &#x1f4e2;歡迎點贊 &#x1f44d; 收藏 ?留言 &#x1…

「優選算法刷題」:刪除字符串中的所有相鄰重復項

一、題目 給出由小寫字母組成的字符串 S&#xff0c;重復項刪除操作會選擇兩個相鄰且相同的字母&#xff0c;并刪除它們。 在 S 上反復執行重復項刪除操作&#xff0c;直到無法繼續刪除。 在完成所有重復項刪除操作后返回最終的字符串。答案保證唯一。 示例&#xff1a; 輸…

理解C#里面的集合有哪些?怎么用,什么是安全集合?

介紹 在C#中&#xff0c;集合是一種用于存儲和操作多個元素的數據結構。它們提供了各種操作&#xff0c;如添加、刪除、查找等&#xff0c;以及遍歷集合中的元素。集合通常根據其實現方式和行為特征進行分類。 集合繼承IEnumerable 在C#中&#xff0c;幾乎所有的集合類型都實現…

簡歷中自我評價,是否應該刪掉?

你好&#xff0c;我是田哥 年后&#xff0c;不少朋友已經開始著手準備面試了&#xff0c;準備面試的第一個問題就是&#xff1a;簡歷。 寫簡歷是需要一些技巧的&#xff0c;你的簡歷是要給面試官看&#xff0c;得多留點心。 很多簡歷上都會寫自我評價/個人優勢/個人總結等&…

2024有哪些免費的mac蘋果電腦深度清理工具?CleanMyMac X

蘋果電腦用戶們&#xff0c;你們是否經常感到你們的Mac變得不再像剛拆封時那樣迅速、流暢&#xff1f;可能是時候對你的蘋果電腦進行一次深度清理了。在這個時刻&#xff0c;擁有一些高效的深度清理工具就顯得尤為重要。今天&#xff0c;我將介紹幾款優秀的蘋果電腦深度清理工具…

一個Web3項目的收官之作,必然是友好的用戶界面(Web3項目三實戰之四)

正如標題所述,一個對用戶體驗友好的應用,總是會贏得用戶大加贊賞,這是毋庸置疑的。 甭管是web2,亦或是已悄然而至的Web3,能有一個外觀優美、用戶體驗效果佳的的界面,那么,這個應用無疑是個成功的案例。 誠然,Web3項目雖然核心是智能合約攥寫,但用戶界面也是一個DApp不…

【Leetcode每日一刷】哈希表|綱領、242.有效的字母異位詞、349. 兩個數組的交集

綱領 &#x1f517;代碼隨想錄理論部分 關于哈希表這個數據結構就不再重復講了&#xff0c;下面對幾個關鍵點記錄一下&#xff1a; 哈希碰撞 解決方法1&#xff1a;拉鏈法 解決方法2&#xff1a;線性探測法 下面針對做題要用到的三種結構講一下&#xff08;也是重復造輪子了…

vue.config.js publicPath 和 vue-router base 結合配置項目根目錄為二級目錄案例

背景: 同個域名下需要有 PC 管理后臺, H5 端, 企業微信 ......等多個端, 需要在一個域名下通過不同的路徑來區分不同的項目; 例如: abc.com/pc, abc.com/h5, abc.com/wx-work.... 此處做個記錄 步驟: 1. 修改 vue.config.js 中的 publicPath module.exports {outputDir:…

MATLAB|【免費】概率神經網絡的分類預測--基于PNN的變壓器故障診斷

目錄 主要內容 部分代碼 結果一覽 下載鏈接 主要內容 ?《MATLAB神經網絡43個案例分析》共有43章&#xff0c;內容涵蓋常見的神經網絡&#xff08;BP、RBF、SOM、Hopfield、Elman、LVQ、Kohonen、GRNN、NARX等&#xff09;以及相關智能算法&#xff08;SVM、決策…

Java 下載excel文件

一、背景 微信小程序需要導出excel文件&#xff0c;后端技術Java&#xff0c;前端使用uniapp框架&#xff0c;使用excel模板。 二、excel 報表模板 需要補充的內容是以下標記問號的&#xff0c;其中有個表格&#xff0c;內容是動態添加的 三、Java端代碼實現 關鍵步驟&…

Topaz Video AI:一鍵提升視頻品質,智能重塑影像魅力 mac/win版

Topaz Video AI是一款革命性的視頻智能處理軟件&#xff0c;它利用先進的機器學習和人工智能技術&#xff0c;為視頻創作者提供了前所未有的視頻增強和修復功能。無論您是專業視頻編輯師、攝影師&#xff0c;還是熱愛視頻創作的愛好者&#xff0c;Topaz Video AI都能幫助您輕松…

webpack打包效率優化,webpack打包體積優化

優化 webpack 打包效率的方法 使用增量構建和熱更新&#xff1a;在開發環境下&#xff0c;使用增量構建和熱更新功能&#xff0c;只重新構建修改過的模塊&#xff0c;減少整體構建時間。避免無意義的工作&#xff1a;在開發環境中&#xff0c;避免執行無意義的工作&#xff0c…

2403C++,C++20協程庫

原文 基于C20協程的http庫--cinatra cinatra是基于C20無棧協程實現的跨平臺,僅頭,高性能,易用的http/https庫(http1.1),包括httpserver和httpclient,功能完備,不僅支持最普通的getpost等請求,還支持restfulapi,websocket,chunked,ranges,multipart,靜態文件服務和反向代理等功…

Python程序的流程

歸納編程學習的感悟&#xff0c; 記錄奮斗路上的點滴&#xff0c; 希望能幫到一樣刻苦的你&#xff01; 如有不足歡迎指正&#xff01; 共同學習交流&#xff01; &#x1f30e;歡迎各位→點贊 &#x1f44d; 收藏? 留言?&#x1f4dd; 年輕是我們唯一擁有權利去編制夢想的時…

【前端素材】推薦優質后臺管理系統Annex平臺模板(附源碼)

一、需求分析 1、系統定義 后臺管理系統是一種用于管理網站、應用程序或系統的管理界面&#xff0c;通常由管理員和工作人員使用。它提供了訪問和控制網站或應用程序后臺功能的工具和界面&#xff0c;使其能夠管理用戶、內容、數據和其他各種功能。 2、功能需求 后臺管理系…