Java中多線程的各種姿勢

在Java中,多線程編程是一種強大的并發編程技術,可以讓你同時執行多個任務。Java提供了多種方式來創建和管理線程。以下是Java中給多線程使用的一些主要方法:

  1. 繼承Thread

    • 創建一個新的類繼承自Thread類。
    • 覆蓋run()方法以定義線程的執行行為。
    • 創建該類的實例,并調用其start()方法來啟動線程。
  2. 實現Runnable接口

    • 創建一個類實現Runnable接口,并實現run()方法。
    • 創建Thread類的實例,將實現了Runnable接口的類的實例作為參數傳給Thread的構造函數。
    • 調用Thread實例的start()方法來啟動線程。
  3. 使用Executor框架

    • Executor框架提供了一種高級的線程管理和任務調度機制。
    • 可以通過Executors類的靜態工廠方法創建不同類型的線程池,如newFixedThreadPoolnewCachedThreadPool等。
    • 使用線程池,可以通過execute()方法提交實現了Runnable接口的任務,或者通過submit()方法提交實現了Callable接口的任務。
  4. 使用FutureCallable

    • Callable接口類似于Runnable,不同之處在于Callable可以返回結果并能拋出異常。
    • 提交Callable任務給ExecutorService后,會返回一個Future對象,通過這個對象可以獲取任務執行結果或取消任務。
  5. 使用ForkJoin框架

    • ForkJoin框架專為大規模并行計算設計,它利用工作竊取算法來提高CPU的利用率。
    • 繼承RecursiveTask(有返回值)或RecursiveAction(無返回值),實現它們的compute方法來定義分支和合并的邏輯。
    • 創建ForkJoinPool實例并提交ForkJoinTask

以上是Java中實現多線程的一些常用方法及同步機制。根據具體的應用場景和需求,開發者可以選擇適合的方法來實現并發編程。

1.Thread線程使用方法

Thread是Java中實現多線程程序的基本單位。每個Thread對象都代表了一個線程的實例。Java中的線程是通過java.lang.Thread類來實現的。Thread類本身實現了Runnable接口,允許你覆蓋其run()方法,定義線程執行的任務。

  • Thread類是實現線程的一種方式。每個Thread對象代表一個線程的實例。
  • 通過繼承Thread類并重寫其run()方法來創建一個新的線程。run()方法定義了線程的執行行為。
  • 創建Thread類的實例后,可以調用其start()方法來啟動線程,這會導致run()方法的執行。

1.1.Thread的核心特性

  • 簡單性:直接繼承Thread類并覆蓋run()方法,就可以定義線程的任務。
  • 直接控制:由于是直接操作線程對象,可以很容易地管理和控制線程的狀態(如開始、暫停、繼續、中斷)。
  • 限制性:由于Java是單繼承的,如果你的類已經繼承了另一個類,就不能通過繼承Thread類的方式來創建線程。

1.2.代碼樣例

  
public class MyThread extends Thread {  public MyThread(String threadName){  this.setName(threadName);  }  public void run() {  for (int i = 0; i < 20; i++) {  // 打印正在執行的線程名稱  System.out.println(Thread.currentThread().getName() + " Value " + i);  }  }  
}public class ThreadExample  {  public static void runDemo(){  // 創建線程  MyThread t1 = new MyThread("線程1");  MyThread t2 = new MyThread("線程2");  // 啟動線程  t1.start();  t2.start();  }  
}public class DemoMain {  public static void main(String[] args) {  ThreadExample.runDemo();  }  
}
  • 輸出結果
線程1 Value 0
線程2 Value 0
線程2 Value 1
線程2 Value 2
線程2 Value 3
線程2 Value 4
線程2 Value 5
線程1 Value 1
線程2 Value 6
線程1 Value 2
線程2 Value 7
線程1 Value 3
線程2 Value 8
線程1 Value 4
線程2 Value 9
線程1 Value 5
線程2 Value 10
線程1 Value 6
線程2 Value 11
線程1 Value 7
線程2 Value 12
線程1 Value 8
線程2 Value 13
線程1 Value 9
線程2 Value 14
線程1 Value 10
線程2 Value 15
線程1 Value 11
線程2 Value 16
線程1 Value 12
線程2 Value 17
線程1 Value 13
線程2 Value 18
線程1 Value 14
線程2 Value 19
線程1 Value 15
線程1 Value 16
線程1 Value 17
線程1 Value 18
線程1 Value 19

1.3.Thread的其他細節操作

1.3.1.等待線程結束(join)

class ThreadJoinExample extends Thread {public void run() {for (int i = 0; i < 5; i++) {try {Thread.sleep(500); // 模擬執行任務System.out.println(Thread.currentThread().getName() + " index=" + i);} catch (InterruptedException e) {System.out.println("Thread interrupted.");}}}public static void main(String[] args) {ThreadJoinExample t1 = new ThreadJoinExample();ThreadJoinExample t2 = new ThreadJoinExample();t1.start();try {t1.join(); // 等待t1執行完成} catch (InterruptedException e) {e.printStackTrace();}t2.start();}
}

1.3.2.中斷線程(interrupt)

  • interrupt()方法用于中斷線程。如果線程因為調用Object.wait()Thread.join()Thread.sleep()方法而被阻塞,它將拋出一個InterruptedException
  • 線程可以通過檢查中斷狀態來優雅地終止執行。
class ThreadInterruptExample extends Thread {public void run() {try {for (int i = 0; i < 5; i++) {Thread.sleep(1000); // 模擬執行任務System.out.println(Thread.currentThread().getName() + " index=" + i);}} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + " Interrupted");}}public static void main(String[] args) {ThreadInterruptExample t1 = new ThreadInterruptExample();t1.start();try {Thread.sleep(3000); // 讓t1有足夠的時間運行} catch (InterruptedException e) {e.printStackTrace();}t1.interrupt(); // 請求中斷t1線程}
}

1.3.3.設置和檢查線程的優先級

  • 線程的優先級通過整數表示,范圍從Thread.MIN_PRIORITY(1)到Thread.MAX_PRIORITY(10)。默認優先級為Thread.NORM_PRIORITY(5)。
  • 可以使用setPriority(int)方法來設置線程的優先級,并使用getPriority()來檢查優先級。
class ThreadPriorityExample extends Thread {public void run() {System.out.println(Thread.currentThread().getName() + " Priority: " + Thread.currentThread().getPriority());}public static void main(String[] args) {ThreadPriorityExample t1 = new ThreadPriorityExample();ThreadPriorityExample t2 = new ThreadPriorityExample();t1.setPriority(Thread.MIN_PRIORITY);t2.setPriority(Thread.MAX_PRIORITY);t1.start();t2.start();}
}

1.3.4.守護線程(Daemon Thread)

  • 守護線程是一種在后臺運行的線程,當所有的非守護線程都結束時,守護線程會自動終止。
  • 可以通過setDaemon(true)方法將線程設置為守護線程,默認情況下,線程是非守護線程。
Thread daemonThread = new Thread(() -> {while (true) {// 執行后臺任務}
});
daemonThread.setDaemon(true); // 將線程設置為守護線程
daemonThread.start();

1.3.5.線程睡眠(Sleep)

  • Thread.sleep()方法使當前線程暫停執行一段時間,以毫秒為單位。
  • 睡眠期間,線程不會釋放鎖,因此其他線程無法訪問被當前線程持有的鎖。
try {Thread.sleep(1000); // 線程睡眠1秒
} catch (InterruptedException e) {e.printStackTrace();
}

1.3.6.線程等待(Wait)與喚醒(Notify)

  • wait()方法使線程進入等待狀態,直到其他線程調用相同對象上的notify()notifyAll()方法喚醒它。
  • 必須在同步塊中使用wait()notify()方法,否則會拋出IllegalMonitorStateException異常。
synchronized (object) {object.wait(); // 線程等待
}
synchronized (object) {object.notify(); // 喚醒一個等待線程// 或者使用 object.notifyAll(); 喚醒所有等待線程
}

1.3.7.注意事項

  • 避免使用Thread.stop():由于它是不安全的,Java已經棄用了stop()方法來停止線程。它會導致線程立即終止,而不會進行任何清理操作,可能會產生不一致的狀態。應該使用中斷和檢查機制來優雅地終止線程。
  • 優先級只是給線程調度器一個提示:線程的優先級并不能保證執行順序或者執行時間。線程調度器可能會忽略這些優先級,特別是在不同的操作系統上。
  • 中斷是一種協作機制:線程需要定期檢查其中斷狀態,并相應地優雅地終止。

2.Runnable線程使用方法

2.1.Runnable的核心特性

Runnable接口是Java中用于表示可運行任務的標準接口,它是實現多線程的一種方式。其核心特性如下:

  1. 抽象任務Runnable接口定義了一個抽象方法run(),用于表示具體的任務邏輯。實現Runnable接口的類需要實現run()方法,將具體的任務邏輯放在其中。

  2. 無返回值run()方法沒有返回值,它是一個void類型的方法。因此,Runnable接口表示的是一種無返回值的任務。

  3. 多線程支持:實現Runnable接口的類可以被多個線程共享,多個線程可以同時執行同一個Runnable對象的run()方法。

  4. 線程與任務解耦Runnable接口將任務的定義與線程的實現解耦,使得任務可以在不同的線程中執行,從而提高了代碼的靈活性和可復用性。

  5. 可與Thread類結合使用Runnable接口通常與Thread類結合使用,通過創建一個Thread對象并將Runnable對象作為參數傳遞給Thread對象的構造方法,來創建并啟動一個新線程。

  6. 適用性廣泛:由于其簡單、靈活的特性,Runnable接口適用于各種需要并發執行的任務,可以用于各種場景,包括但不限于并行計算、異步處理、任務調度等。

綜上所述,Runnable接口是實現多線程的一種基本方式,它定義了一個抽象的任務,并提供了一種通用的方式來表示可運行的任務,適用于各種需要并發執行的場景。

2.2. 代碼樣例

public class MyRunnable implements Runnable {  public void run() {  for (int i = 0; i < 20; i++) {  System.out.println(Thread.currentThread().getName() + " Value " + i);  }  }  
}
public class RunnableExample {  public static void runDemo(){  // 創建Runnable實例  MyRunnable myRunnable = new MyRunnable();  // 創建Thread對象,并將Runnable實例作為目標對象傳遞給Thread構造器  Thread t1 = new Thread(myRunnable);  Thread t2 = new Thread(myRunnable);  // 啟動線程  t1.start();  t2.start();  }  
}
  • 輸出結果
Thread-0 Value 0
Thread-1 Value 0
Thread-0 Value 1
Thread-0 Value 2
Thread-0 Value 3
Thread-1 Value 1
Thread-1 Value 2
Thread-1 Value 3
Thread-1 Value 4
Thread-0 Value 4
Thread-0 Value 5
Thread-0 Value 6
Thread-0 Value 7
Thread-0 Value 8
Thread-0 Value 9
Thread-0 Value 10
Thread-0 Value 11
Thread-0 Value 12
Thread-0 Value 13
Thread-0 Value 14
Thread-0 Value 15
Thread-1 Value 5
Thread-0 Value 16
Thread-1 Value 6
Thread-0 Value 17
Thread-1 Value 7
Thread-0 Value 18
Thread-1 Value 8
Thread-0 Value 19
Thread-1 Value 9
Thread-1 Value 10
Thread-1 Value 11
Thread-1 Value 12
Thread-1 Value 13
Thread-1 Value 14
Thread-1 Value 15
Thread-1 Value 16
Thread-1 Value 17
Thread-1 Value 18
Thread-1 Value 19

3.Thread和Runnable 區別

ThreadRunnable是實現多線程程序的兩種基本方式,它們各有特點和適用場景。以下是ThreadRunnable之間的主要區別:

3.1. 繼承與實現的區別

  • Thread:是一個類,繼承Thread類來創建線程意味著你的線程類不能再繼承其他類,因為Java不支持多重繼承。
  • Runnable:是一個接口,實現Runnable接口如果你的類已經繼承了另一個類,你仍然可以通過實現Runnable接口來創建線程。

3.2. 設計靈活性

  • Thread:直接繼承Thread類可能會限制類的擴展性,因為你的類已經繼承了Thread,它不能再繼承其他類。
  • Runnable:實現Runnable接口更加靈活,它允許你的類繼承其他類,在多個線程間共享相同的資源。

3.3. 資源共享

  • Thread:每個Thread類的實例都是一個單獨的對象,它們之間的資源不共享,除非顯式地使用外部資源。
  • Runnable:多個線程可以共享同一個Runnable實例,因此它們可以訪問相同的資源,這使得在多個線程之間共享數據和行為變得更加容易。

3.4. 適用場景

  • Thread:當你的線程不需要訪問共享資源或你只是創建少量線程時,繼承Thread類可能是一個簡單的選擇。
  • Runnable:當你需要多個線程共享數據或資源,或者你的類已經繼承了另一個類時,實現Runnable接口是更好的選擇。

3.5. 推薦做法

雖然兩種方式都可以用來創建線程,但實踐中更推薦實現Runnable接口,原因包括:

  • 實現Runnable接口的方式更加靈活,允許繼承其他類并實現多個接口。
  • 它支持多個線程共享同一個Runnable實例,便于線程間的資源共享。
  • Executor框架結合使用時,通常要求提供RunnableCallable任務,而不是Thread對象。

總的來說,雖然直接使用Thread類可以簡化某些編程場景,但實現Runnable接口提供了更高的靈活性和資源共享的能力,因此在多數情況下更被推薦。

4.Executor線程池的使用方法

Executor是Java中用于執行任務的框架,它提供了一種將任務提交與任務執行分離的方式,可以更好地管理和控制線程的創建和執行。Executor框架使得并發編程變得更加簡單和可控,可以有效地利用系統資源,提高程序的性能和可擴展性。

4.1.Executor框架的核心組件

  1. Executor接口Executor是一個接口,它定義了單一的方法execute(Runnable command),用于執行給定的任務。

  2. ExecutorService接口ExecutorServiceExecutor的子接口,它擴展了Executor接口,提供了更豐富的功能。主要包括:

    • 提交任務并返回Future對象,用于追蹤任務的執行狀態和結果。
    • 管理線程池的生命周期,包括啟動、關閉、終止等。
  3. ThreadPoolExecutor類ThreadPoolExecutorExecutorService接口的一個具體實現,它是一個靈活的線程池實現,可以根據需要自動調整線程數量。

  4. Executors工廠類Executors類是一個工廠類,提供了創建各種類型線程池的靜態方法,如newFixedThreadPoolnewCachedThreadPoolnewSingleThreadExecutor等。

  5. ScheduledExecutorService接口ScheduledExecutorServiceExecutorService的一個子接口,它提供了可以延遲執行或定期執行任務的功能。

4.2.Executor框架的優點

  1. 簡化并發編程Executor框架將任務的提交和執行分離開來,簡化了并發編程的復雜性。
  2. 提高資源利用率:通過使用線程池,可以重復利用已創建的線程,減少了線程的創建和銷毀開銷。
  3. 提高性能:通過并行執行多個任務,可以加快任務的執行速度,提高程序的性能。
  4. 提高可管理性Executor框架提供了一系列方法來管理線程池的狀態和行為,如監控線程池的執行狀態、設置線程池的大小等。

4.3.代碼樣例

public class CustomThreadFactory implements ThreadFactory {  private String threadNamePrefix;  public CustomThreadFactory(String threadNamePrefix) {  this.threadNamePrefix = threadNamePrefix;  }  @Override  public Thread newThread(Runnable r) {  Thread thread = new Thread(r);  // 設置線程名稱  thread.setName(threadNamePrefix + "-" + thread.getId());  return thread;  }  
}public class ExecutorExample {  public static void runDemo() {  // 創建自定義的ThreadFactory  ThreadFactory threadFactory = new CustomThreadFactory("Xiaocai_CustomThread");  // 創建固定大小的線程池  ExecutorService executor = Executors.newFixedThreadPool(5,threadFactory);  // 提交任務  for (Integer i = 0; i < 10; i++) {  final Integer threadIndex=i;  executor.execute(new MyThread(threadIndex.toString()));  }  System.out.println("關閉線程池之前");  // 關閉線程池  executor.shutdown();  System.out.println("關閉線程池之后");  try {  executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("線程池中所有線程執行完畢");  }  
}
  • 輸出結果
已連接到目標 VM, 地址: ''127.0.0.1:14181',傳輸: '套接字''
Xiaocai_CustomThread-12 Value 0
關閉線程池之前
Xiaocai_CustomThread-14 Value 0
Xiaocai_CustomThread-14 Value 1
Xiaocai_CustomThread-14 Value 2
Xiaocai_CustomThread-14 Value 3
Xiaocai_CustomThread-14 Value 4
Xiaocai_CustomThread-16 Value 0
Xiaocai_CustomThread-16 Value 1
Xiaocai_CustomThread-16 Value 2
Xiaocai_CustomThread-16 Value 3
Xiaocai_CustomThread-12 Value 1
Xiaocai_CustomThread-12 Value 2
Xiaocai_CustomThread-12 Value 3
Xiaocai_CustomThread-12 Value 4
Xiaocai_CustomThread-12 Value 5
Xiaocai_CustomThread-12 Value 6
關閉線程池之后
Xiaocai_CustomThread-16 Value 4
Xiaocai_CustomThread-14 Value 5
Xiaocai_CustomThread-14 Value 6
Xiaocai_CustomThread-16 Value 5
Xiaocai_CustomThread-16 Value 6
Xiaocai_CustomThread-16 Value 7
Xiaocai_CustomThread-16 Value 8
Xiaocai_CustomThread-16 Value 9
Xiaocai_CustomThread-18 Value 0
Xiaocai_CustomThread-20 Value 0
Xiaocai_CustomThread-20 Value 1
Xiaocai_CustomThread-12 Value 7
Xiaocai_CustomThread-20 Value 2
Xiaocai_CustomThread-18 Value 1
Xiaocai_CustomThread-16 Value 10
Xiaocai_CustomThread-16 Value 11
Xiaocai_CustomThread-14 Value 7
Xiaocai_CustomThread-14 Value 8
Xiaocai_CustomThread-14 Value 9
Xiaocai_CustomThread-16 Value 12
Xiaocai_CustomThread-18 Value 2
Xiaocai_CustomThread-18 Value 3
Xiaocai_CustomThread-18 Value 4
Xiaocai_CustomThread-20 Value 3
Xiaocai_CustomThread-12 Value 8
Xiaocai_CustomThread-20 Value 4
Xiaocai_CustomThread-18 Value 5
Xiaocai_CustomThread-16 Value 13
Xiaocai_CustomThread-14 Value 10
Xiaocai_CustomThread-16 Value 14
Xiaocai_CustomThread-18 Value 6
Xiaocai_CustomThread-20 Value 5
Xiaocai_CustomThread-12 Value 9
Xiaocai_CustomThread-20 Value 6
Xiaocai_CustomThread-18 Value 7
Xiaocai_CustomThread-16 Value 15
Xiaocai_CustomThread-14 Value 11
Xiaocai_CustomThread-16 Value 16
Xiaocai_CustomThread-18 Value 8
Xiaocai_CustomThread-20 Value 7
Xiaocai_CustomThread-12 Value 10
Xiaocai_CustomThread-20 Value 8
Xiaocai_CustomThread-18 Value 9
Xiaocai_CustomThread-16 Value 17
Xiaocai_CustomThread-14 Value 12
Xiaocai_CustomThread-16 Value 18
Xiaocai_CustomThread-18 Value 10
Xiaocai_CustomThread-20 Value 9
Xiaocai_CustomThread-12 Value 11
Xiaocai_CustomThread-20 Value 10
Xiaocai_CustomThread-18 Value 11
Xiaocai_CustomThread-16 Value 19
Xiaocai_CustomThread-14 Value 13
Xiaocai_CustomThread-18 Value 12
Xiaocai_CustomThread-20 Value 11
Xiaocai_CustomThread-12 Value 12
Xiaocai_CustomThread-20 Value 12
Xiaocai_CustomThread-18 Value 13
Xiaocai_CustomThread-16 Value 0
Xiaocai_CustomThread-14 Value 14
Xiaocai_CustomThread-16 Value 1
Xiaocai_CustomThread-18 Value 14
Xiaocai_CustomThread-20 Value 13
Xiaocai_CustomThread-12 Value 13
Xiaocai_CustomThread-20 Value 14
Xiaocai_CustomThread-18 Value 15
Xiaocai_CustomThread-16 Value 2
Xiaocai_CustomThread-14 Value 15
Xiaocai_CustomThread-16 Value 3
Xiaocai_CustomThread-18 Value 16
Xiaocai_CustomThread-20 Value 15
Xiaocai_CustomThread-12 Value 14
Xiaocai_CustomThread-20 Value 16
Xiaocai_CustomThread-18 Value 17
Xiaocai_CustomThread-16 Value 4
Xiaocai_CustomThread-14 Value 16
Xiaocai_CustomThread-16 Value 5
Xiaocai_CustomThread-18 Value 18
Xiaocai_CustomThread-20 Value 17
Xiaocai_CustomThread-12 Value 15
Xiaocai_CustomThread-20 Value 18
Xiaocai_CustomThread-18 Value 19
Xiaocai_CustomThread-16 Value 6
Xiaocai_CustomThread-14 Value 17
Xiaocai_CustomThread-16 Value 7
Xiaocai_CustomThread-18 Value 0
Xiaocai_CustomThread-20 Value 19
Xiaocai_CustomThread-12 Value 16
Xiaocai_CustomThread-20 Value 0
Xiaocai_CustomThread-18 Value 1
Xiaocai_CustomThread-16 Value 8
Xiaocai_CustomThread-14 Value 18
Xiaocai_CustomThread-16 Value 9
Xiaocai_CustomThread-18 Value 2
Xiaocai_CustomThread-20 Value 1
Xiaocai_CustomThread-12 Value 17
Xiaocai_CustomThread-20 Value 2
Xiaocai_CustomThread-18 Value 3
Xiaocai_CustomThread-16 Value 10
Xiaocai_CustomThread-14 Value 19
Xiaocai_CustomThread-16 Value 11
Xiaocai_CustomThread-18 Value 4
Xiaocai_CustomThread-20 Value 3
Xiaocai_CustomThread-12 Value 18
Xiaocai_CustomThread-20 Value 4
Xiaocai_CustomThread-18 Value 5
Xiaocai_CustomThread-16 Value 12
Xiaocai_CustomThread-14 Value 0
Xiaocai_CustomThread-16 Value 13
Xiaocai_CustomThread-18 Value 6
Xiaocai_CustomThread-20 Value 5
Xiaocai_CustomThread-12 Value 19
Xiaocai_CustomThread-12 Value 0
Xiaocai_CustomThread-20 Value 6
Xiaocai_CustomThread-18 Value 7
Xiaocai_CustomThread-16 Value 14
Xiaocai_CustomThread-14 Value 1
Xiaocai_CustomThread-16 Value 15
Xiaocai_CustomThread-18 Value 8
Xiaocai_CustomThread-20 Value 7
Xiaocai_CustomThread-12 Value 1
Xiaocai_CustomThread-20 Value 8
Xiaocai_CustomThread-18 Value 9
Xiaocai_CustomThread-16 Value 16
Xiaocai_CustomThread-14 Value 2
Xiaocai_CustomThread-16 Value 17
Xiaocai_CustomThread-18 Value 10
Xiaocai_CustomThread-20 Value 9
Xiaocai_CustomThread-12 Value 2
Xiaocai_CustomThread-20 Value 10
Xiaocai_CustomThread-18 Value 11
Xiaocai_CustomThread-16 Value 18
Xiaocai_CustomThread-14 Value 3
Xiaocai_CustomThread-16 Value 19
Xiaocai_CustomThread-18 Value 12
Xiaocai_CustomThread-20 Value 11
Xiaocai_CustomThread-12 Value 3
Xiaocai_CustomThread-20 Value 12
Xiaocai_CustomThread-18 Value 13
Xiaocai_CustomThread-14 Value 4
Xiaocai_CustomThread-18 Value 14
Xiaocai_CustomThread-20 Value 13
Xiaocai_CustomThread-12 Value 4
Xiaocai_CustomThread-20 Value 14
Xiaocai_CustomThread-18 Value 15
Xiaocai_CustomThread-14 Value 5
Xiaocai_CustomThread-18 Value 16
Xiaocai_CustomThread-20 Value 15
Xiaocai_CustomThread-12 Value 5
Xiaocai_CustomThread-20 Value 16
Xiaocai_CustomThread-18 Value 17
Xiaocai_CustomThread-14 Value 6
Xiaocai_CustomThread-18 Value 18
Xiaocai_CustomThread-20 Value 17
Xiaocai_CustomThread-12 Value 6
Xiaocai_CustomThread-20 Value 18
Xiaocai_CustomThread-18 Value 19
Xiaocai_CustomThread-14 Value 7
Xiaocai_CustomThread-20 Value 19
Xiaocai_CustomThread-12 Value 7
Xiaocai_CustomThread-12 Value 8
Xiaocai_CustomThread-14 Value 8
Xiaocai_CustomThread-12 Value 9
Xiaocai_CustomThread-14 Value 9
Xiaocai_CustomThread-12 Value 10
Xiaocai_CustomThread-14 Value 10
Xiaocai_CustomThread-12 Value 11
Xiaocai_CustomThread-14 Value 11
Xiaocai_CustomThread-12 Value 12
Xiaocai_CustomThread-14 Value 12
Xiaocai_CustomThread-12 Value 13
Xiaocai_CustomThread-14 Value 13
Xiaocai_CustomThread-12 Value 14
Xiaocai_CustomThread-14 Value 14
Xiaocai_CustomThread-12 Value 15
Xiaocai_CustomThread-14 Value 15
Xiaocai_CustomThread-12 Value 16
Xiaocai_CustomThread-14 Value 16
Xiaocai_CustomThread-12 Value 17
Xiaocai_CustomThread-14 Value 17
Xiaocai_CustomThread-12 Value 18
Xiaocai_CustomThread-14 Value 18
Xiaocai_CustomThread-12 Value 19
Xiaocai_CustomThread-14 Value 19
線程池中所有線程執行完畢
與目標 VM 斷開連接, 地址為: ''127.0.0.1:14181',傳輸: '套接字''進程已結束,退出代碼為 0

在上面的示例中,通過Executors.newFixedThreadPool(5)方法創建了一個固定大小為5的線程池,然后提交了10個任務。線程池會自動管理這些任務的執行,使用合適數量的線程執行任務。最后通過executor.shutdown()方法關閉線程池。

總之,Executor框架提供了一種高級的、靈活的方式來執行任務,是Java并發編程中的重要工具之一,值得深入學習和應用。

4.4.細節操作

4.4.1.怎么判斷線程池中所有線程全部運行完畢呢?

		System.out.println("關閉線程池之前");  // 關閉線程池  executor.shutdown();  System.out.println("關閉線程池之后");  try {  executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("線程池中所有線程執行完畢");  

4.4.2.調用executor.shutdown()的目的

調用executor.shutdown()方法的目的是關閉線程池,即停止接受新的任務,并嘗試將已提交但尚未開始執行的任務從任務隊列中移除,同時等待已經提交的任務執行完畢。主要原因包括:

  1. 釋放資源:線程池在執行完所有任務后,會保持活動狀態,并且等待新的任務。如果不關閉線程池,線程池中的線程將一直存在,占用系統資源(如內存等),可能導致資源浪費。

  2. 避免任務丟失:如果不關閉線程池,那么主程序執行完畢后可能會立即結束,導致尚未執行完的任務丟失。

  3. 優雅關閉:調用shutdown()方法后,線程池不會立即關閉,而是等待之前提交的任務執行完成后關閉,保證已提交的任務能夠被執行完畢,避免任務中途被打斷。

  4. 避免線程泄露:如果不關閉線程池,線程池中的線程可能會一直存在,即使主程序已經執行完畢,導致線程泄露問題。

因此,一般情況下,在不再需要線程池時應該及時調用shutdown()方法來關閉線程池,以釋放資源并確保已提交的任務能夠正常執行完畢。

5.Future使用方法

Future是Java中表示異步計算結果的接口,它提供了一種機制,可以在任務執行完成之前先提交任務,并且在需要結果時獲取任務執行的結果。通過Future,可以在任務執行的過程中進行其他操作,而不必阻塞等待任務執行完成。

5.1.Future的核心特性

  1. 表示異步計算結果Future接口表示一個異步計算的結果。可以通過get()方法來獲取計算的結果,如果計算尚未完成,則會阻塞直到計算完成。

  2. 取消任務Future提供了cancel()方法用于取消任務的執行。如果任務已經完成,或者由于其他原因無法取消,則cancel()方法返回false

  3. 判斷任務狀態isDone()方法用于判斷任務是否完成,isCancelled()方法用于判斷任務是否被取消。

5.2.代碼樣例

public class FutureExample {  public static void runDemo() {  // 創建線程池  ExecutorService executor = Executors.newFixedThreadPool(1);  // 提交任務并獲取Future對象  Future<Integer> future = executor.submit(new Callable<Integer>() {  @Override  public Integer call() throws Exception {  // 模擬一個耗時的任務  Thread.sleep(2000);  return 42;  }  });  // 其他操作...  System.out.println("Do something else while waiting for the result...");  try {  // 獲取任務結果,如果任務尚未完成,會阻塞直到任務完成  Integer result = future.get();  System.out.println("Result: " + result);  } catch (InterruptedException | ExecutionException e) {  e.printStackTrace();  }  // 關閉線程池  executor.shutdown();  }  
}

6.Callable使用方法

Callable是Java中用于表示可調用任務的接口,與Runnable接口類似,但它可以返回結果并且能夠拋出異常。通常與ExecutorService一起使用,通過submit(Callable)方法提交Callable任務,并返回一個Future對象,用于獲取任務的執行結果。

6.1.Callable的核心特性

  1. 返回結果Callable接口使用泛型來定義返回類型,可以通過call()方法返回計算的結果。

  2. 拋出異常call()方法可以拋出異常,允許任務執行過程中發生異常情況。

6.2.使用示例

public class CallableExample {  public static void runDemo() {  // 創建線程池  ExecutorService executor = Executors.newFixedThreadPool(1);  // 提交Callable任務并獲取Future對象  Future<Integer> future = executor.submit(new MyCallable());  // 其他操作...  System.out.println("Do something else while waiting for the result...");  try {  // 獲取任務結果,如果任務尚未完成,會阻塞直到任務完成  Integer result = future.get();  System.out.println("Result: " + result);  } catch (InterruptedException | ExecutionException e) {  e.printStackTrace();  }  // 關閉線程池  executor.shutdown();  }  
}public class MyCallable implements Callable<Integer> {  @Override  public Integer call() throws Exception {  // 模擬一個耗時的任務  Thread.sleep(2000);  return 42;  }  
}

在上面的示例中,首先創建了一個固定大小為1的線程池。然后通過executor.submit(Callable)方法提交一個Callable任務,并獲得一個Future對象。在任務執行的過程中,可以執行其他操作,而不必等待任務完成。當需要任務結果時,調用future.get()方法,如果任務已經完成,則立即返回結果;如果任務尚未完成,則會阻塞直到任務完成,并返回結果。

總之,Callable接口允許在任務執行過程中返回結果和拋出異常,提供了一種更加靈活和功能豐富的任務定義方式,適用于需要異步計算結果的場景。

7.ForkJoin使用方法

ForkJoin框架是Java中用于并行計算的框架,它基于"分而治之"的思想,能夠有效地利用多核處理器的優勢,加速任務的執行速度。ForkJoin框架提供了ForkJoinPoolForkJoinTaskRecursiveTask等類來支持并行計算。

ForkJoin框架的核心特性

  1. 任務分解ForkJoin框架通過遞歸的方式將大任務劃分為小任務,然后并行執行這些小任務,從而實現任務的分解和并行處理。

  2. 工作竊取ForkJoin框架中的ForkJoinPool使用工作竊取算法來管理線程池中的工作線程。當一個工作線程沒有任務可執行時,它會從其他工作線程的任務隊列中偷取任務來執行,從而實現負載均衡。

  3. 遞歸任務ForkJoinTaskForkJoin框架中表示任務的抽象類,它有兩個主要子類:RecursiveActionRecursiveTask,分別用于沒有返回值的任務和有返回值的任務。

使用示例

下面是一個使用ForkJoin框架計算數組元素之和的示例:

public class ForkJoinExample {  public static void runDemo() {  // 創建ForkJoinPool  ForkJoinPool pool = new ForkJoinPool();  // 創建一個大數組  int[] array = new int[1000];  for (int i = 0; i < array.length; i++) {  array[i] = i + 1;  }  // 創建ForkJoin任務  ForkJoinTask<Integer> task = new SumTask(array, 0, array.length);  // 提交任務并獲取結果  Integer result = pool.invoke(task);  // 輸出結果  System.out.println("Sum of array elements: " + result);  // 關閉線程池  pool.shutdown();  }  
}class SumTask extends RecursiveTask<Integer> {private int[] array;private int start;private int end;public SumTask(int[] array, int start, int end) {this.array = array;this.start = start;this.end = end;}@Overrideprotected Integer compute() {if (end - start <= 10) {// 如果任務規模小于等于10,直接計算結果int sum = 0;for (int i = start; i < end; i++) {sum += array[i];}return sum;} else {// 否則將任務分解成兩個子任務int mid = (start + end) / 2;SumTask leftTask = new SumTask(array, start, mid);SumTask rightTask = new SumTask(array, mid, end);// 并行執行子任務leftTask.fork();rightTask.fork();// 合并子任務的結果int leftResult = leftTask.join();int rightResult = rightTask.join();// 返回結果return leftResult + rightResult;}}
}

在上面的示例中,首先創建了一個ForkJoinPool,然后創建了一個包含1000個元素的數組。接著創建了一個ForkJoinTask(這里使用了RecursiveTask的子類SumTask),并將其提交給ForkJoinPool進行執行。SumTask任務負責計算數組的元素之和,如果任務規模較小,則直接計算結果;否則將任務分解成兩個子任務,分別計算子數組的元素之和,然后合并結果。

總之,ForkJoin框架通過任務的分解和并行執行,能夠提高任務的執行效率,特別適用于處理大規模的數據并且任務之間存在遞歸關系的場景。

8.對比一下Thread、Runnable、Executor、Future、Callable、ForkJoin這幾種線程操作的方式,對比他們之間的異同點,以及使用場景

下面是對Thread、Runnable、Executor、Future、Callable和ForkJoin這幾種線程操作方式的異同點以及使用場景的對比:

8.1. Thread

  • 方式:直接繼承Thread類,覆寫run()方法。
  • 異同點:與其他方式相比,使用起來更為簡單直觀,但線程和任務的耦合性較強,不利于任務的復用和資源的管理。
  • 使用場景:適用于簡單的并發任務,不需要共享資源或狀態的場景。

8.2. Runnable

  • 方式:實現Runnable接口,實現run()方法。
  • 異同點:相比于直接繼承Thread類,實現Runnable接口的方式更為靈活,可以更好地支持任務的復用和資源的管理。
  • 使用場景:適用于需要共享資源或狀態的場景,也適用于已經繼承其他類的情況下,無法再繼承Thread類。

8.3. Executor

  • 方式:通過Executor框架來管理和執行任務。
  • 異同點:相比于直接創建線程,使用Executor框架能夠更好地管理線程資源,提高線程的復用性和可管理性。
  • 使用場景:適用于需要管理和調度多個任務的場景,例如批量處理任務、任務隊列等。

8.4. Future

  • 方式:通過Future接口來獲取異步計算的結果。
  • 異同點Future接口提供了異步計算結果的獲取方式,允許任務的提交和獲取結果的操作分離開來,提高了程序的并發性能。
  • 使用場景:適用于需要等待異步任務完成并獲取結果的場景,例如并行計算、I/O操作等。

8.5. Callable

  • 方式:實現Callable接口,實現call()方法。
  • 異同點:與Runnable接口類似,但Callable接口允許任務返回結果和拋出異常,功能更為豐富。
  • 使用場景:適用于需要任務返回結果或拋出異常的場景,例如需要等待任務執行完成并獲取結果的場景。

8.6. ForkJoin

  • 方式:通過ForkJoin框架實現任務的并行計算。
  • 異同點:相比于傳統的線程池,ForkJoin框架提供了任務分解和工作竊取等機制,能夠更有效地利用多核處理器的優勢。
  • 使用場景:適用于需要大規模并行計算的場景,例如遞歸任務的分解、歸并排序等。

綜上所述,不同的線程操作方式有不同的特點和適用場景。直接使用ThreadRunnable接口適合簡單的并發任務;Executor框架適合管理和調度多個任務的場景;FutureCallable接口適合需要等待任務完成并獲取結果的場景;ForkJoin框架適合需要大規模并行計算的場景。在實際應用中,根據具體的需求選擇合適的線程操作方式能夠更好地提高程序的性能和可維護性。

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

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

相關文章

爬蟲案例一

首先我舉一個案例比如豆瓣電影排行榜 (douban.com)這個電影&#xff0c;首先我們進去檢查源代碼 說明源代碼有&#xff0c;說明是服務器渲染&#xff0c;可以直接那html 但是返回的結果是空&#xff0c;所以我們需要在頭里面加上User-Agent 然后可以看到有返回的結果&#xff0…

Docker快速集成minio

拉取鏡像&#xff08;默認最新的&#xff09; docker pull minio/minio創建配制和數據映射文件夾&#xff08;用于將容器內的配置和數據映射到本地&#xff09; 這邊的路徑可以修改成自己想要的文件夾 mkdir -p /data/minio/{config,data}啟動容器 (這邊啟動容器要保證本地映…

什么是SpringCloud,有哪些組件?

spring Cloud 是基于spring boot的分布式系統開發工具,它提供了一系列開箱即用的,針對分布式系統開發的特性和組件。用于幫助開發人員快速構建和管理云原生應用程序。 Spring Cloud 的主要目標是解決分布式系統中的常見問題,例如服務發現,負載均衡,配置管理,斷路器,消息總…

c++筆記—— AutoBuffer類(opencv)

自動分配緩沖區類 Automatically Allocated Buffer Class. 這個類用于函數和方法中的臨時緩沖區。如果臨時緩沖區通常很小&#xff08;幾K的內存&#xff09;&#xff0c;但其大小取決于參數&#xff0c;則在堆棧上創建一個小的固定大小數組&#xff0c;并在足夠大時使用它是有…

LabVIEW起重機工作參數遠程監測系統

LabVIEW起重機工作參數遠程監測系統 隨著起重機技術的持續發展&#xff0c;對其工作參數的實時監控需求日益增加。設計了一個基于LabVIEW和TBox的起重機工作參數遠程監測系統&#xff0c;能夠實現起重機工作參數的實時采集、傳輸、解析和顯示&#xff0c;有效提升起重機的性能…

python--開心篇--print--多種多樣的print輸出

文章目錄 名言輸出繞口令輸出《水滸傳》中的梁山好漢輸出軌道交通充值信息輸出對聯字符畫輸出長春地鐵1號線運行圖模擬12306查詢界面模擬企業網站登錄界面 名言 print("& "*15) print("& &") print("& …

發現了一個超級好用的上網神器!但是不知道在哪里有賣······隨身WiFi好評推薦,隨身WiFi好用嗎?

這兩天到一個小地方出差&#xff0c; 走到一個奶茶店附近&#xff0c; 突然老板打電話說一個緊急文件需要我處理&#xff0c; 說實話有點崩潰&#xff0c; 前不著村后不著店的&#xff0c; 我去哪里找網絡辦公 辛虧奶茶店的小姐姐聽到了&#xff0c; 讓我在她店里&#x…

wy的leetcode刷題記錄_Day81

wy的leetcode刷題記錄_Day81 聲明 本文章的所有題目信息都來源于leetcode 如有侵權請聯系我刪掉! 時間&#xff1a;2024-3-4 前言 目錄 wy的leetcode刷題記錄_Day81聲明前言232. 用棧實現隊列題目介紹思路代碼收獲 138. 隨機鏈表的復制題目介紹思路代碼收獲 141. 環形鏈表題…

SUSE 配置防火墻策略

一.獲取目前訪問的接口 suse12sp3 # netstat -tunlp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:8005 0.0.0.0:* …

【Bugs】class path resource [xxx.xml] cannot be opened because it does not exist

報錯&#xff1a; 關鍵報錯信息&#xff1a; class path resource [scope.xml] cannot be opened because it does not exist完整報錯信息&#xff1a; 2024-03-01 14:26:58 866 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refres…

Ubuntu的apt、apt-get和apt-cache命令

原文&#xff1a;apt 和 apt-get 之間有什么區別&#xff1f; https://aws.amazon.com/cn/compare/the-difference-between-apt-and-apt-get/ 陳拓轉載&#xff0c;2023/11/23&#xff0c;添加了舉例。 apt 和 apt-get 之間有什么區別&#xff1f; apt 和 apt-get 都是命令行…

【存儲】without SPDK時,fio測試nvme SSD 和HDD對比

先看使用的io調度器是什么,SSD的話最好設置成none。 root@xxx-0010 ~ # cat /sys/block/nvme5n1/queue/scheduler [none] mq-deadline kyber使用fio對nvme SSD和普通HDD做對比測試: 1、 4K random write fio -filename=/data12/fiotest/testfile -direct=1 -iodepth=4 -th…

OpenAI劃時代大模型——文本生成視頻模型Sora作品欣賞(十五)

Sora介紹 Sora是一個能以文本描述生成視頻的人工智能模型&#xff0c;由美國人工智能研究機構OpenAI開發。 Sora這一名稱源于日文“空”&#xff08;そら sora&#xff09;&#xff0c;即天空之意&#xff0c;以示其無限的創造潛力。其背后的技術是在OpenAI的文本到圖像生成模…

如何找到企查查天眼查上沒有的企業聯系方式?

相信很多銷售在查找企業聯系方式的過程中&#xff0c;遇到過很多問題。很多人在出入行的時候都使用過企查查&#xff0c;天眼查來查找客戶。 但是在實際工作中使用這上面的聯系方式&#xff0c;效果卻不是很理想&#xff0c;因為上面的信息不是很準確&#xff0c;號碼不是企業…

【嵌入式移植】8、U-Boot源碼分析5—啟動過程分析start.S

U-Boot源碼分析5—啟動過程分析start.S 1、boot0.h2、reset2.1、vectors2.2、ELn2.2.1 EL32.2.2、EL2、EL1 2.3、SMPEN2.3、core errate2.4、lowlevel_init 前面從U-Boot編譯的角度分析了其Makefile、鏈接腳本等&#xff0c;本章開始正式分析U-Boot啟動過程 從上一篇文章7、U-…

ClickHouse SQL Reference (四)數據類型

Tuple(T1, T2, …) 元素元組&#xff0c;每個元素都有一個單獨的類型。元組必須至少包含一個元素。 元組用于臨時列分組。在查詢中使用IN表達式時&#xff0c;以及指定lambda函數的某些形式參數時&#xff0c;可以對列進行分組。有關更多信息&#xff0c;請參閱IN操作符和高階…

u-boot 基礎學習:板級配置 Kconfig 的包含

前言 u-boot 與 Linux 內核在嵌入式Linux開發中占有重要的地位&#xff0c;掌握 u-boot 的基礎開發&#xff0c;可以大大提升開發能力&#xff0c;并提高開發的效率。 u-boot 下 如何配置 板級的Kconfig 呢&#xff1f;u-boot 下板級的 Kconfig 是怎么包含到 主目錄下 Kconfig…

【代碼隨想錄算法訓練營Day34】860.檸檬水找零;406.根據身高重建隊列;452.用最少數量的箭引爆氣球

??Day 34 第八章 貪心算法 part04 ??今日任務 860.檸檬水找零406.根據身高重建隊列452.用最少數量的箭引爆氣球 ??860.檸檬水找零 本題看上好像挺難&#xff0c;其實挺簡單的&#xff0c;大家先嘗試自己做一做。題目鏈接&#xff1a;https://leetcode.cn/problems/lem…

【計算機網絡】IO多路轉接之poll

文章目錄 一、poll函數接口二、socket就緒條件三、poll的優點四、poll的缺點五、poll使用案例--只讀取數據的server服務器1.err.hpp2.log.hpp3.sock.hpp4.pollServer.hpp5.main.cc 一、poll函數接口 #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int t…

2024.3.3 訓練記錄(7)

這幾天又忘記每天復習了&#xff0c;以后在實驗室復習完再回去好了 最近做1800的題目好多dp啊太ex了 文章目錄 牛客 練習賽122D 圓CF 1396B Stoned GameCF 1355C Count TrianglesCF 1437C Chef MonocarpCF 271D Good SubstringsCF 1475D Cleaning the PhoneCF 1362D2 Prefix-…