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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java并发编程基础系列(五): 创建线程的四种方式

發布時間:2025/3/20 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java并发编程基础系列(五): 创建线程的四种方式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

線程的創建一共有四種方式:

  • 繼承于Thread類,重寫run()方法;
  • 實現Runable接口,實現里面的run()方法;
  • 使用 FutureTask 實現有返回結果的線程
  • 使用ExecutorService、Executors 線程池。

在詳細了解這四種方法之前,先來理解一下為什么線程要這樣創建:形象點來說,Thread是一個工人,run()方法里面的便是他的任務欄,這個任務欄默認是空的。當你想要這個線程做點什么時,你可以重寫Thread里面的run方法,重寫這個工人的任務欄;也可以通過runable、callable接口,從外部賦予這個工人任務。還可以將任務交給一堆工人,誰有空就誰就承擔這個任務(線程池)。

一、四種方式的詳細介紹

1、繼承于Thread類,重寫run()方法

Thread thread = new MyThread();//線程啟動 thread.start();

MyThread 類

//繼承Thread class MyThread extends Thread{//重寫run方法@Overridepublic void run() {//任務內容....System.out.println("當前線程是:"+Thread.currentThread().getName());} }

運行結果:
當前線程是:Thread-0

如果線程類使用的很少,那么可以使用匿名內部類,請看下面的例子:

Thread thread = new Thread(){@Overridepublic void run() {//任務內容....System.out.println("當前線程是:"+Thread.currentThread().getName());}};

2、實現Runable接口,實現里面的run()方法:

第一種方法- -繼承Thread類的方法,一般情況下是不建議用的,因為java是單繼承結構,一旦繼承了Thread類,就無法繼承其他類了。所以建議使用 實現Runable接口 的方法;

Thread thread = new Thread(new MyTask());//線程啟動 thread.start();

MyTask 類:

//實現Runnable接口 class MyTask implements Runnable{//重寫run方法public void run() {//任務內容....System.out.println("當前線程是:"+Thread.currentThread().getName());} }

同樣,如果這個任務類(MyTask )用的很少,也可以使用匿名內部類:

Thread thread = new Thread(new Runnable() {@Overridepublic void run() {//任務內容....System.out.println("當前線程是:"+Thread.currentThread().getName());}});

3、使用 FutureTask 實現有返回結果的線程

FutureTask 是一個可取消的異步計算任務,是一個獨立的類,實現了 Future、Runnable接口。FutureTask 的出現是為了彌補 Thread 的不足而設計的,可以讓程序員跟蹤、獲取任務的執行情況、計算結果
??因為 FutureTask實現了 Runnable,所以 FutureTask 可以作為參數來創建一個新的線程來執行,也可以提交給 Executor 執行。FutureTask 一旦計算完成,就不能再重新開始或取消計算。

FutureTask的構造方法

可以接受 Runnable,Callable 的子類實例。

//創建一個 FutureTask,一旦運行就執行給定的 Callable。 public FutureTask(Callable<V> callable);//創建一個 FutureTask,一旦運行就執行給定的 Runnable,并安排成功完成時 get 返回給定的結果 。 public FutureTask(Runnable runnable, V result)

FutureTask 的簡單例子

public class Test {public static void main(String[] args) throws InterruptedException, ExecutionException {FutureTask<Double> task = new FutureTask(new MyCallable());//創建一個線程,異步計算結果Thread thread = new Thread(task);thread.start();//主線程繼續工作Thread.sleep(1000);System.out.println("主線程等待計算結果...");//當需要用到異步計算的結果時,阻塞獲取這個結果Double d = task.get();System.out.println("計算結果是:"+d);//用同一個 FutureTask 再起一個線程Thread thread2 = new Thread(task);thread2.start(); } }class MyCallable implements Callable<Double>{@Overridepublic Double call() {double d = 0;try {System.out.println("異步計算開始.......");d = Math.random()*10;d += 1000;Thread.sleep(2000);System.out.println("異步計算結束.......");} catch (InterruptedException e) {e.printStackTrace();}return d;} }

運行結果:
異步計算開始…
主線程等待計算結果…
異步計算結束…
計算結果是:1002.7806590582911

四、使用線程池ExecutorSerice、Executors

前面三種方法,都是顯式地創建一個線程,可以直接控制線程,如線程的優先級、線程是否是守護線程,線程何時啟動等等。而第四種方法,則是創建一個線程池,池中可以有1個或多個線程,這些線程都是線程池去維護,控制程序員不需要關心這些細節,只需要將任務提交給線程池去處理便可,非常方便。
??創建線程池的前提最好是你的任務量大,因為創建線程池的開銷比創建一個線程大得多。

創建線程池的方式

ExecutorService 是一個比較重要的接口,實現這個接口的子類有兩個 ThreadPoolExecutor (普通線程池)、ScheduleThreadPoolExecutor (定時任務的線程池)。你可以通過這兩個類來創建一個線程池,但要傳入各種參數,不太方便。
??為了方便用戶,JDK中提供了工具類Executors,提供了幾個創建常用的線程池的工廠方法。由于篇幅原因,不細說,可參考我的并發系列文章。

Executors 創建單線程的線程池

public class MyTest {public static void main(String[] args) {//創建一個只有一個線程的線程池ExecutorService executorService = Executors.newSingleThreadExecutor();//創建任務,并提交任務到線程池中executorService.execute(new MyRunable("任務1"));executorService.execute(new MyRunable("任務2"));executorService.execute(new MyRunable("任務3"));} }class MyRunable implements Runnable{private String taskName;public MyRunable(String taskName) {this.taskName = taskName;}@Overridepublic void run() {System.out.println("線程池完成任務:"+taskName);} }

二、關于run()方法的思考

看看下面這種情況:線程類Thread 接收了外部任務,同時又用匿名內部類的方式重寫了內部的run()方法,這樣豈不是有兩個任務,那么究竟會執行那個任務呢?還是兩個任務一起執行呢?

Thread thread = new Thread(new MyTask()){@Overridepublic void run() {//重寫Thread類的run方法System.out.println("Thread 類的run方法");}};//線程啟動thread.start(); //實現Runnable接口 class MyTask implements Runnable{//重寫run方法@Overridepublic void run() {//任務內容....System.out.println("這是Runnable的run方法");} }

運行結果:
Thread 類的run方法

通過上面的結果,可以看出:線程最后執行的是Thread類內部的run()方法,這是為什么呢?我們先來分析一下JDK的Thread源碼:

private Runnable target;public void run() { if (target != null) { target.run(); } }

一切都清晰明了了,Thread類的run方法在沒有重寫的情況下,是判斷一下是否有Runnable 對象傳進來,如果有,那么就調用Runnable 對象里的run方法;否則,就什么都不干,線程結束。所以,針對上面的例子,一旦你繼承重寫了Thread類的run()方法,而你又想可以接收Runable類的對象,那么就要加上super.run(),執行沒有重寫時的run方法,改造的例子如下:

Thread thread = new Thread(new MyTask()){@Overridepublic void run() {//重寫Thread類的run方法//調用父類Thread的run方法,即沒有重寫時的run方法super.run();System.out.println("Thread 類的run方法");}};

運行結果:
這是Runnable的run方法
Thread 類的run方法

  • 出處:http://www.cnblogs.com/jinggod/p/8485106.html

總結

以上是生活随笔為你收集整理的java并发编程基础系列(五): 创建线程的四种方式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。