日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

多线程的几种实现方法

發(fā)布時間:2025/5/22 编程问答 10 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多线程的几种实现方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Java多線程的使用有三種方法:繼承Thread類、實(shí)現(xiàn)Runnable接口和使用Callable和Future創(chuàng)建線程,本文將對這三種方法一一進(jìn)行介紹。

1、繼承Thread類

實(shí)現(xiàn)方式很簡單,只需要創(chuàng)建一個類去繼承Thread類然后重寫run方法,在main方法中調(diào)用該類實(shí)例對象的start方法即可實(shí)現(xiàn)多線程并發(fā)。代碼:

public class MyThread extends Thread {
@Override
public void run(){
super.run();
System.out.println(“執(zhí)行子線程…”);
}
}
測試用例:

public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
System.out.println(“主線程…”);
}
}
運(yùn)行結(jié)果:

當(dāng)然,這里的結(jié)果不代表線程的執(zhí)行順序,線程是并發(fā)執(zhí)行的,如果多運(yùn)行幾次,打印順序可能會不一樣。多線程的運(yùn)行過程中,CPU是以不確定的方式去執(zhí)行線程的,故運(yùn)行結(jié)果與代碼的執(zhí)行順序或者調(diào)用順序無關(guān),運(yùn)行結(jié)果也可能不一樣。關(guān)于線程執(zhí)行的隨機(jī)性本文后面也有代碼示例。

這里還有一個需要注意的點(diǎn)就是main方法中應(yīng)該調(diào)用的是myThread的start方法,而不是run()方法。調(diào)用start()方法是告訴CPU此線程已經(jīng)準(zhǔn)備就緒可以執(zhí)行,進(jìn)而系統(tǒng)有時間就會來執(zhí)行其run()方法。而直接調(diào)用run()方法,則不是異步執(zhí)行,而是等同于調(diào)用函數(shù)般按順序同步執(zhí)行,這就失去了多線程的意義了。

2、實(shí)現(xiàn)Runnable接口

這種方式的實(shí)現(xiàn)也很簡單,就是把繼承Thread類改為實(shí)現(xiàn)Runnable接口。代碼如下:

public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(“執(zhí)行子線程…”);
}
}
測試用例:

public class Test {
public static void main(String[] args) {

Runnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start();System.out.println("主線程運(yùn)行結(jié)束!"); }

}
運(yùn)行結(jié)果:

運(yùn)行結(jié)果沒啥好說的,這里main中可以看到真正創(chuàng)建新線程還是通過Thread創(chuàng)建:

Thread thread = new Thread(runnable);
這一步Thread類的作用就是把run()方法包裝成線程執(zhí)行體,然后依然通過start去告訴系統(tǒng)這個線程已經(jīng)準(zhǔn)備好了可以安排執(zhí)行。

3、使用Callable和Future創(chuàng)建線程

上面的兩種方式都有這兩個問題:

  • 無法獲取子線程的返回值
  • run方法不可以拋出異常

為了解決這兩個問題,我們就需要用到Callable這個接口了。說到接口,上面的Runnable接口實(shí)現(xiàn)類實(shí)例是作為Thread類的構(gòu)造函數(shù)的參數(shù)傳入的,之后通過Thread的start執(zhí)行run方法中的內(nèi)容。但是Callable并不是Runnable的子接口,是個全新的接口,它的實(shí)例不能直接傳入給Thread構(gòu)造,所以需要另一個接口來轉(zhuǎn)換一下。

Java5提供了Future接口來代表Callable接口里call()方法的返回值,并為Future接口提供了一個實(shí)現(xiàn)類FutureTask,該實(shí)現(xiàn)類的繼承關(guān)系如圖所示:

可以看到,該實(shí)現(xiàn)類不僅實(shí)現(xiàn)了Future接口,還實(shí)現(xiàn)了Runnable接口,所以可以直接傳給Thread構(gòu)造函數(shù)。

而關(guān)于FutureTask的構(gòu)造函數(shù)如下:

所以這里面其實(shí)就是要比上一個方法再多一個轉(zhuǎn)換過程,最終一樣是通過Thread的start來創(chuàng)建新線程。有了這個思路,代碼就很容易理解了:

import java.util.concurrent.Callable;

public class MyCallable implements Callable {
int i = 0;
@Override
public Object call() throws Exception {
System.out.println(Thread.currentThread().getName()+" i的值:"+ i);
return i++; //call方法可以有返回值
}
}
測試:

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Test {
public static void main(String[] args) {
Callable callable = new MyCallable();
for (int i = 0; i < 10; i++) {
FutureTask task = new FutureTask(callable);
new Thread(task,“子線程”+ i).start();
try {
//獲取子線程的返回值
System.out.println(“子線程返回值:”+task.get() + “\n”);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
執(zhí)行結(jié)果(部分):

4、線程執(zhí)行的隨機(jī)性

上面介紹第一種方法的時候,說了線程的執(zhí)行順序與start()的執(zhí)行順序無關(guān),而是CPU有空隙了就過來執(zhí)行該線程,所以具有隨機(jī)性,執(zhí)行順序也是隨機(jī)的。

示例代碼:

public class MyThread extends Thread {
int i;
public MyThread(int i){
super();
this.i = i;
}
@Override
public void run(){
System.out.println(i);
}
}
測試代碼:

public class Test {
Thread thread1 = new MyThread(1);
Thread thread2 = new MyThread(2);
Thread thread3 = new MyThread(3);
Thread thread4 = new MyThread(4);
Thread thread5 = new MyThread(5);
Thread thread6 = new MyThread(6);
Thread thread7 = new MyThread(7);
Thread thread8 = new MyThread(8);
Thread thread9 = new MyThread(9);
Thread thread10 = new MyThread(10);

thread1.start();thread2.start();thread3.start();thread4.start();thread5.start();thread6.start();thread7.start();thread8.start();thread9.start();thread10.start(); }

}

運(yùn)行結(jié)果體現(xiàn)了這一點(diǎn):

5、三種方式的對比

第一種和后面兩種的對比:
1、通過代碼可以看出,第一種方法是最簡潔方便的,直接就可以start,不需要任何轉(zhuǎn)換
2、但是第一種有一個很不好的地方就是繼承了Thread類后由于java的單繼承機(jī)制,就不可以繼承其他的類了,而如果實(shí)現(xiàn)的是接口,就可以實(shí)現(xiàn)多個接口,使開發(fā)更靈活。

第二種和第三種方式對比:
1、同樣的,第二種方法相對第三種方式來說代碼更簡潔,使用更方便,少了一次轉(zhuǎn)換
2、第三種方法有兩個優(yōu)點(diǎn):有返回值、可以拋出異常

總結(jié)

實(shí)際開發(fā)中可能有更復(fù)雜的代碼實(shí)現(xiàn),需要繼承其他的類,所以平時更推薦通過實(shí)現(xiàn)接口來實(shí)現(xiàn)多線程,也就是通過第二或第三種方式來實(shí)現(xiàn),這樣能保持代碼靈活和解耦。
而選擇第二還是第三種方式,則要根據(jù)run()方法是不是需要返回值或者捕獲異常來決定,如果不需要,可以選擇用第二種方式實(shí)現(xiàn),代碼更簡潔。

總結(jié)

以上是生活随笔為你收集整理的多线程的几种实现方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。