本文將介紹一下Java多線程的用法。
基礎(chǔ)介紹
什么是多線程
指的是在一個進(jìn)程中同時運行多個線程,每個線程都可以獨立執(zhí)行不同的任務(wù)或操作。 與單線程相比,多線程可以提高程序的并發(fā)性和響應(yīng)能力。
什么是進(jìn)程
是指正在運行的程序的實例。
每個進(jìn)程都擁有自己的內(nèi)存空間、代碼、數(shù)據(jù)和文件等資源,可以獨立運行、調(diào)度和管理。在操作系統(tǒng)中,進(jìn)程是系統(tǒng)資源分配的最小單位,是實現(xiàn)多任務(wù)的基礎(chǔ)。
Java多線程
Java多線程是指在一個Java程序中同時執(zhí)行多個線程,它可以提高程序的并發(fā)性和響應(yīng)能力。Java中實現(xiàn)多線程的方式:
繼承Thread類
繼承Thread類是實現(xiàn)多線程的一種方式,只需要繼承Thread類并重寫run()方法即可。
public class ThreadDemo {
public static void main(String[] args) {
// 創(chuàng)建10個線程并啟動
for (int i = 0; i < 10; i++) {
MyThread thread = new MyThread(i);
thread.start();
}
}
}
class MyThread extends Thread {
private int id;
public MyThread(int id) {
this.id = id;
}
public void run() {
System.out.println("Thread " + id + " is running");
try {
Thread.sleep(1000); // 模擬任務(wù)執(zhí)行時間
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
以上代碼中,首先創(chuàng)建了一個ThreadDemo類,在main函數(shù)中創(chuàng)建了10個線程,并啟動這些線程。
每個線程都是MyThread類的實例,MyThread類繼承了Thread類,并重寫了run()方法,在方法中模擬了一個需要執(zhí)行1秒鐘的任務(wù)。
在main函數(shù)中,通過創(chuàng)建MyThread類的實例,并調(diào)用start()方法啟動線程。start()方法會調(diào)用線程的run()方法,在run()方法中執(zhí)行線程的任務(wù)。
實現(xiàn)Runnable接口
另一種實現(xiàn)多線程的方式是實現(xiàn)Runnable接口,需要實現(xiàn)run()方法,并將實現(xiàn)了Runnable接口的對象傳遞給Thread類的構(gòu)造函數(shù)。
public class RunnableDemo {
public static void main(String[] args) {
// 創(chuàng)建10個線程并啟動
for (int i = 0; i < 10; i++) {
Runnable task = new MyTask(i);
Thread thread = new Thread(task);
thread.start();
}
}
}
class MyTask implements Runnable {
private int id;
public MyTask(int id) {
this.id = id;
}
public void run() {
System.out.println("Thread " + id + " is running");
try {
Thread.sleep(1000); // 模擬任務(wù)執(zhí)行時間
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
以上代碼中,創(chuàng)建了一個RunnableDemo類,在main函數(shù)中創(chuàng)建了10個線程,并啟動這些線程。
每個線程都是MyTask類的實例,MyTask類實現(xiàn)了Runnable接口,并重寫了run()方法,在方法中模擬了一個需要執(zhí)行1秒鐘的任務(wù)。
在main函數(shù)中,通過創(chuàng)建MyTask類的實例,并創(chuàng)建一個Thread對象,將Runnable對象作為參數(shù)傳遞給Thread構(gòu)造方法,最后調(diào)用start()方法啟動線程。start()方法會調(diào)用線程的run()方法,在run()方法中執(zhí)行線程的任務(wù)。
在使用實現(xiàn)Runnable接口實現(xiàn)多線程時,可以更好地分離任務(wù)和線程,并提高代碼的可擴展性和可維護(hù)性。
如果需要添加更多的線程或任務(wù),只需要創(chuàng)建更多的Runnable實例,并創(chuàng)建對應(yīng)的Thread對象即可,不需要創(chuàng)建更多的線程類,并且可以更好地重用代碼。
Executor框架
Executor框架是Java提供的一個線程池框架,用于管理和調(diào)度多個線程。通過Executor框架,可以更方便地實現(xiàn)多線程,避免手動管理線程帶來的復(fù)雜性和風(fēng)險。
Executor框架的核心接口是Executor和ExecutorService,
- Executor是一個簡單的線程池接口,只有一個execute()方法,用于提交一個Runnable任務(wù)給線程池執(zhí)行。
- ExecutorService是Executor的擴展接口,提供了更多的管理和調(diào)度線程的方法,如submit()、shutdown()、awaitTermination()等。
使用Executor框架實現(xiàn)多線程,通常需要以下步驟:
- 創(chuàng)建一個ExecutorService對象,可以使用Executors類提供的靜態(tài)方法創(chuàng)建線程池,如newFixedThreadPool()、newCachedThreadPool()、newSingleThreadExecutor()等。
- 將需要執(zhí)行的任務(wù)封裝成一個Runnable或Callable對象,可以使用Java中的匿名內(nèi)部類或Lambda表達(dá)式來創(chuàng)建。
- 將任務(wù)提交給ExecutorService對象執(zhí)行,可以使用submit()方法提交Callable對象,或使用execute()方法提交Runnable對象。
- 在程序完成時,調(diào)用shutdown()方法關(guān)閉線程池,或使用awaitTermination()方法等待所有線程執(zhí)行完畢。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorDemo {
public static void main(String[] args) {
// 創(chuàng)建一個包含10個線程的線程池
ExecutorService executor = Executors.newFixedThreadPool(10);
// 提交10個任務(wù)給線程池執(zhí)行
for (int i = 0; i < 10; i++) {
executor.execute(new MyTask(i));
}
// 關(guān)閉線程池
executor.shutdown();
}
}
class MyTask implements Runnable {
private int id;
public MyTask(int id) {
this.id = id;
}
public void run() {
System.out.println("Thread " + id + " is running");
try {
Thread.sleep(1000); // 模擬任務(wù)執(zhí)行時間
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上面的例子中,先創(chuàng)建了一個ExecutorDemo類,在main函數(shù)中創(chuàng)建了一個包含10個線程的線程池。
每個線程池中的線程都可以執(zhí)行MyTask類的實例,MyTask類實現(xiàn)了Runnable接口,并重寫了run()方法,在方法中模擬了一個需要執(zhí)行1秒鐘的任務(wù)。
在main函數(shù)中,創(chuàng)建MyTask類的實例,并調(diào)用ExecutorService的execute()方法提交給線程池執(zhí)行。
execute()方法會將任務(wù)提交給線程池中的一個空閑線程執(zhí)行。
最后調(diào)用ExecutorService的shutdown()方法關(guān)閉線程池。
需要注意的是,shutdown()方法會等待所有線程執(zhí)行完畢后才會關(guān)閉線程池,如果需要立即關(guān)閉線程池,可以使用shutdownNow()方法。
Callable實現(xiàn)多線程
Callable是Java中的一個接口,與Runnable接口類似,都用于封裝一個線程執(zhí)行的任務(wù)。
不同的是,Callable接口的call()方法可以返回一個結(jié)果,而Runnable接口的run()方法沒有返回值。
使用Callable實現(xiàn)多線程,通常需要以下步驟:
- 創(chuàng)建一個實現(xiàn)了Callable接口的類,實現(xiàn)call()方法,并在方法中編寫線程執(zhí)行的代碼。
- 創(chuàng)建一個ExecutorService對象,可以使用Executors類提供的靜態(tài)方法創(chuàng)建線程池,如newFixedThreadPool()、newCachedThreadPool()、newSingleThreadExecutor()等。
- 將Callable對象提交給ExecutorService對象執(zhí)行,可以使用submit()方法提交。
- 調(diào)用Future對象的get()方法獲取Callable線程執(zhí)行的結(jié)果。
- 在程序完成時,調(diào)用shutdown()方法關(guān)閉線程池,或使用awaitTermination()方法等待所有線程執(zhí)行完畢。
import java.util.concurrent.*;
public class CallableDemo {
public static void main(String[] args) throws Exception {
// 創(chuàng)建一個線程池
ExecutorService executor = Executors.newFixedThreadPool(10);
// 提交10個Callable任務(wù)給線程池執(zhí)行
Future< Integer >[] results = new Future[10];
for (int i = 0; i < 10; i++) {
Callable< Integer > task = new MyTask(i);
results[i] = executor.submit(task);
}
// 輸出Callable任務(wù)的執(zhí)行結(jié)果
for (int i = 0; i < 10; i++) {
Integer result = results[i].get();
System.out.println("Task " + i + " result is " + result);
}
// 關(guān)閉線程池
executor.shutdown();
}
}
class MyTask implements Callable< Integer > {
private int id;
public MyTask(int id) {
this.id = id;
}
public Integer call() throws Exception {
System.out.println("Task " + id + " is running");
Thread.sleep(1000); // 模擬任務(wù)執(zhí)行時間
return id * 10;
}
}
首先創(chuàng)建一個線程池,然后提交10個Callable任務(wù)給線程池執(zhí)行。每個Callable任務(wù)都是MyTask類的實例,MyTask類實現(xiàn)了Callable接口,并重寫了call()方法,在方法中模擬了一個需要執(zhí)行1秒鐘的任務(wù),并返回一個結(jié)果。
詳細(xì)解釋如下:
- 創(chuàng)建一個線程池,通過調(diào)用Executors的靜態(tài)方法newFixedThreadPool(10),創(chuàng)建了一個固定大小為10的線程池。
- 在for循環(huán)中,通過創(chuàng)建MyTask類的實例,將其封裝為Callable對象,并通過ExecutorService的submit()方法提交給線程池執(zhí)行。submit()方法會返回一個Future對象,代表了Callable任務(wù)的執(zhí)行結(jié)果。
- 在for循環(huán)中,通過Future數(shù)組記錄每個Callable任務(wù)的執(zhí)行結(jié)果,可以通過調(diào)用get()方法獲取Callable任務(wù)的執(zhí)行結(jié)果。如果Callable任務(wù)還沒有執(zhí)行完成,get()方法會阻塞當(dāng)前線程,直到任務(wù)執(zhí)行完成并返回結(jié)果。如果任務(wù)執(zhí)行過程中發(fā)生異常,get()方法會拋出ExecutionException異常。
- 在任務(wù)完成后,可以通過調(diào)用Future對象的get()方法獲取任務(wù)的執(zhí)行結(jié)果,并打印輸出。
- 最后調(diào)用ExecutorService的shutdown()方法關(guān)閉線程池,應(yīng)該在所有任務(wù)執(zhí)行完成后才能關(guān)閉線程池。
注意,在使用Callable實現(xiàn)多線程時,要考慮線程安全、同步機制、任務(wù)調(diào)度和管理等問題,以確保程序的正確性和穩(wěn)定性。
同時,由于Callable任務(wù)的執(zhí)行時間可能會比較長,可以設(shè)置超時時間來避免任務(wù)執(zhí)行時間過長導(dǎo)致的程序阻塞。
Future實現(xiàn)多線程
Future是Java中的一個接口,用于異步獲取任務(wù)執(zhí)行結(jié)果。
在多線程編程中,可以使用Future來獲取異步任務(wù)的執(zhí)行結(jié)果,以便在任務(wù)完成后進(jìn)行處理或展示。
使用Future實現(xiàn)多線程,需要以下步驟:
- 創(chuàng)建一個實現(xiàn)了Callable接口的類,實現(xiàn)call()方法,并在方法中編寫線程執(zhí)行的代碼。
- 創(chuàng)建一個ExecutorService對象,可以使用Executors類提供的靜態(tài)方法創(chuàng)建線程池,如newFixedThreadPool()、newCachedThreadPool()、newSingleThreadExecutor()等。
- 將Callable對象提交給ExecutorService對象執(zhí)行,可以使用submit()方法提交,submit()方法會返回一個Future對象。
- 調(diào)用Future對象的get()方法獲取Callable線程執(zhí)行的結(jié)果。如果任務(wù)還沒有執(zhí)行完成,get()方法會阻塞當(dāng)前線程直到任務(wù)執(zhí)行完成并返回結(jié)果。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class FutureDemo {
public static void main(String[] args) throws Exception {
// 創(chuàng)建一個線程池
ExecutorService executor = Executors.newFixedThreadPool(10);
// 提交10個Callable任務(wù)給線程池執(zhí)行
List< Future< Integer >> results = new ArrayList< >();
for (int i = 0; i < 10; i++) {
Callable< Integer > task = new MyTask(i);
Future< Integer > result = executor.submit(task);
results.add(result);
}
// 輸出Callable任務(wù)的執(zhí)行結(jié)果
for (int i = 0; i < 10; i++) {
Integer result = results.get(i).get();
System.out.println("Task " + i + " result is " + result);
}
// 關(guān)閉線程池
executor.shutdown();
}
}
class MyTask implements Callable< Integer > {
private int id;
public MyTask(int id) {
this.id = id;
}
public Integer call() throws Exception {
System.out.println("Task " + id + " is running");
Thread.sleep(1000); // 模擬任務(wù)執(zhí)行時間
return id * 10;
}
}
在以上示例中:
- 首先創(chuàng)建了一個線程池,然后提交10個Callable任務(wù)給線程池執(zhí)行。每個Callable任務(wù)都是MyTask類的實例,MyTask類實現(xiàn)了Callable接口,并重寫了call()方法,在方法中模擬了一個需要執(zhí)行1秒鐘的任務(wù),并返回一個結(jié)果。
- 在main函數(shù)中,使用List記錄每個Callable任務(wù)的執(zhí)行結(jié)果的Future對象,并在任務(wù)完成后通過調(diào)用get()方法獲取Callable任務(wù)的執(zhí)行結(jié)果。如果任務(wù)還沒有執(zhí)行完成,get()方法會阻塞當(dāng)前線程直到任務(wù)執(zhí)行完成并返回結(jié)果。
- 最后關(guān)閉線程池。
線程池實現(xiàn)多線程
線程池是Java中提供的一個用于管理和復(fù)用多個線程的框架,可以有效地提高多線程應(yīng)用程序的性能和可靠性。
使用線程池實現(xiàn)多線程,通常需要以下步驟:
- 創(chuàng)建一個線程池,可以使用Executors類提供的靜態(tài)方法創(chuàng)建線程池,如newFixedThreadPool()、newCachedThreadPool()、newSingleThreadExecutor()等。
- 創(chuàng)建一個實現(xiàn)了Runnable接口或Callable接口的類,實現(xiàn)run()方法或call()方法,并在方法中編寫線程執(zhí)行的代碼。
- 將Runnable對象或Callable對象提交給線程池執(zhí)行,可以使用submit()方法提交,submit()方法會返回一個Future對象。
- 關(guān)閉線程池,可以調(diào)用shutdown()方法或shutdownNow()方法。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) throws Exception {
// 創(chuàng)建一個包含10個線程的線程池
ExecutorService executor = Executors.newFixedThreadPool(10);
// 提交10個任務(wù)給線程池執(zhí)行,并記錄每個任務(wù)的執(zhí)行結(jié)果
List< Future< Integer >> results = new ArrayList< >();
for (int i = 0; i < 10; i++) {
Callable< Integer > task = new MyTask(i);
Future< Integer > result = executor.submit(task);
results.add(result);
}
// 等待所有任務(wù)執(zhí)行完成
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
// 輸出所有任務(wù)的執(zhí)行結(jié)果
int total = 0;
for (int i = 0; i < 10; i++) {
try {
Integer result = results.get(i).get();
System.out.println("Task " + i + " result is " + result);
total += result;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
System.out.println("Task " + i + " execution error: " + e.getCause().getMessage());
}
}
System.out.println("Total result is " + total);
}
}
class MyTask implements Callable< Integer > {
private int id;
public MyTask(int id) {
this.id = id;
}
public Integer call() throws Exception {
System.out.println("Task " + id + " is running");
Thread.sleep(2000); // 模擬任務(wù)執(zhí)行時間
if (id % 2 == 0) {
throw new RuntimeException("Task " + id + " execution error");
}
return id * 10;
}
}
在以上示例中,首先創(chuàng)建了一個包含10個線程的線程池,然后提交10個任務(wù)給線程池執(zhí)行。每個任務(wù)都是MyTask類的實例,MyTask類實現(xiàn)了Callable接口,并重寫了call()方法,在方法中模擬了一個需要執(zhí)行2秒鐘的任務(wù),并返回一個結(jié)果。
其中,如果任務(wù)的id是偶數(shù),會拋出一個運行時異常。
在main函數(shù)中,使用List記錄每個任務(wù)的執(zhí)行結(jié)果的Future對象,并在任務(wù)完成后通過調(diào)用get()方法獲取任務(wù)的執(zhí)行結(jié)果。
如果任務(wù)還沒有執(zhí)行完成,get()方法會阻塞當(dāng)前線程直到任務(wù)執(zhí)行完成并返回結(jié)果。
在所有任務(wù)提交給線程池后,調(diào)用ExecutorService的shutdown()方法關(guān)閉線程池,并調(diào)用awaitTermination()方法等待所有任務(wù)執(zhí)行完成。
最后輸出所有任務(wù)的執(zhí)行結(jié)果,并計算所有任務(wù)的執(zhí)行結(jié)果的總和。
總結(jié)
總之,Java多線程是提高程序并發(fā)性和響應(yīng)能力的重要手段,需要掌握多線程的實現(xiàn)方式、同步機制、線程之間的通信機制等,以確保多線程程序的正確性和穩(wěn)定性。
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7030瀏覽量
89034 -
JAVA
+關(guān)注
關(guān)注
19文章
2967瀏覽量
104750 -
程序
+關(guān)注
關(guān)注
117文章
3787瀏覽量
81043 -
多線程
+關(guān)注
關(guān)注
0文章
278瀏覽量
19956 -
代碼
+關(guān)注
關(guān)注
30文章
4788瀏覽量
68611
發(fā)布評論請先 登錄
相關(guān)推薦
評論