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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

JUC多线程:创建线程的四种方式

發(fā)布時(shí)間:2024/9/30 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JUC多线程:创建线程的四种方式 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在 Java 中,實(shí)現(xiàn)多線程的主要有以下四種:

(1)繼承 Thread 類,重寫(xiě) run() 方法;

(2)實(shí)現(xiàn) Runnable 接口,實(shí)現(xiàn)?run() 方法,并將 Runnable 實(shí)現(xiàn)類的實(shí)例作為 Thread 構(gòu)造函數(shù)的參數(shù) target;

(3)實(shí)現(xiàn) Callable 接口,實(shí)現(xiàn) call() 方法,然后通過(guò) FutureTask 包裝器來(lái)創(chuàng)建 Thread 線程;

(4)通過(guò) ThreadPoolExecutor 創(chuàng)建線程池,并從線程池中獲取線程用于執(zhí)行任務(wù);

第(1)(2)種方式無(wú)法獲取線程的執(zhí)行結(jié)果,因?yàn)橥ㄟ^(guò)重寫(xiě)的 run()? 方法的返回值是void;第(3)種方式可以獲取線程的執(zhí)行結(jié)果,因?yàn)橥ㄟ^(guò) Callable 接口的 call() 方法的返回值是 Object,可以將返回的結(jié)果可以放在 Object 對(duì)象中;第(4)種方式對(duì)于兩種情況都支持,具體取決于任務(wù)的類型,有返回值的任務(wù)必須實(shí)現(xiàn) Callable 接口,無(wú)返回值的任務(wù)必須實(shí)現(xiàn) Runnable 接口。

1、繼承Thread類的方式:

Thread 實(shí)現(xiàn)了 Runnable 接口,代表一個(gè)線程的實(shí)例。啟動(dòng)線程的唯一方法就是通過(guò) Thread 類的start() 方法。start() 方法是一個(gè)native方法,它將啟動(dòng)一個(gè)新線程,并執(zhí)行run()方法。

這種方式實(shí)現(xiàn)多線程很簡(jiǎn)單,直接 extends?Thread,并重寫(xiě) run() 方法,就可以啟動(dòng)新線程執(zhí)行自己定義的run()方法。例如:

public class MyThread extends Thread { public void run() { System.out.println("MyThread.run()"); } } MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); myThread1.start(); myThread2.start();

2、通過(guò)實(shí)現(xiàn) Runnable 接口:

通過(guò)實(shí)現(xiàn) Runnable 接口,實(shí)現(xiàn) run() 方法,將 Runnable? 接口的實(shí)現(xiàn)類的實(shí)例作為 Thread 的帶參構(gòu)造函數(shù)中,并通過(guò)調(diào)用 start() 方法啟動(dòng)線程,如下:

public class ThreadDemo02 {public static void main(String[] args){ System.out.println(Thread.currentThread().getName());Thread t1 = new Thread(new MyThread());t1.start(); } } class MyThread implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"-->我是通過(guò)實(shí)現(xiàn)接口的線程實(shí)現(xiàn)方式!");} }

實(shí)現(xiàn) Runnable 接口比繼承 Thread 類所具有的優(yōu)勢(shì)主要有:

  • ① 可以避免 JAVA 中單繼承的限制;
  • ② 線程池只能放入實(shí)現(xiàn) Runable 或 Callable類線程,不能直接放入繼承 Thread 的類
  • ③ 代碼可以被多個(gè)線程共享,代碼和數(shù)據(jù)獨(dú)立,適合多個(gè)相同的程序代碼的線程去處理同一個(gè)資源的情況

3、實(shí)現(xiàn)Callable接口,并通過(guò)FutureTask包裝器來(lái)創(chuàng)建Thread線程:

(1)實(shí)現(xiàn)?Callable 接口,并實(shí)現(xiàn) call() 方法;?

(2)創(chuàng)建 Callable 接口的實(shí)現(xiàn)類的實(shí)例,使用 FutureTask 類包裝 Callable 對(duì)象,該 FutureTask 對(duì)象封裝了 Callable 對(duì)象的 call() 方法的返回值;?

(3)使用 FutureTask 對(duì)象作為 Thread 類的構(gòu)造函數(shù)的?target 參數(shù)創(chuàng)建并啟動(dòng)線程;

(4)調(diào)用 FutureTask 對(duì)象的 get() 來(lái)獲取子線程執(zhí)行結(jié)束的返回值;

public class ThreadDemo03 {public static void main(String[] args) {Callable<Object> oneCallable = new Tickets<Object>();FutureTask<Object> oneTask = new FutureTask<Object>(oneCallable);Thread t = new Thread(oneTask);System.out.println(Thread.currentThread().getName());t.start();} } class Tickets<Object> implements Callable<Object>{//重寫(xiě)call方法@Overridepublic Object call() throws Exception {System.out.println(Thread.currentThread().getName()+"-->我是通過(guò)實(shí)現(xiàn)Callable接口通過(guò)FutureTask包裝器來(lái)實(shí)現(xiàn)的線程");return null;} }

4、使用 ThreadPoolExecutor 創(chuàng)建線程池:

使用 ThreadPoolExecutor 創(chuàng)建線程池,并從線程池中獲取線程用于執(zhí)行任務(wù)。在 JUC 中,Executor 框架已經(jīng)實(shí)現(xiàn)了幾種線程池,我們就以?Executor 的 newFixedThreadPool 來(lái)作為 Demo 的展示。

import java.util.concurrent.*; import java.util.Date; import java.util.List; import java.util.ArrayList; /** * 有返回值的線程 */ @SuppressWarnings("unchecked") public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("----程序開(kāi)始運(yùn)行----"); Date date1 = new Date(); int taskSize = 5; // 創(chuàng)建一個(gè)線程池 ExecutorService pool = Executors.newFixedThreadPool(taskSize); // 創(chuàng)建多個(gè)有返回值的任務(wù) List<Future> list = new ArrayList<Future>(); for (int i = 0; i < taskSize; i++) { Callable c = new MyCallable(i + " "); // 執(zhí)行任務(wù)并獲取Future對(duì)象 Future f = pool.submit(c); // System.out.println(">>>" + f.get().toString()); list.add(f); } // 關(guān)閉線程池 pool.shutdown(); // 獲取所有并發(fā)任務(wù)的運(yùn)行結(jié)果 for (Future f : list) { // 從Future對(duì)象上獲取任務(wù)的返回值,并輸出到控制臺(tái) System.out.println(">>>" + f.get().toString()); } Date date2 = new Date(); System.out.println("----程序結(jié)束運(yùn)行----,程序運(yùn)行時(shí)間【" + (date2.getTime() - date1.getTime()) + "毫秒】"); } } class MyCallable implements Callable<Object> { private String taskNum; MyCallable(String taskNum) { this.taskNum = taskNum; } public Object call() throws Exception { System.out.println(">>>" + taskNum + "任務(wù)啟動(dòng)"); Date dateTmp1 = new Date(); Thread.sleep(1000); Date dateTmp2 = new Date(); long time = dateTmp2.getTime() - dateTmp1.getTime(); System.out.println(">>>" + taskNum + "任務(wù)終止"); return taskNum + "任務(wù)返回運(yùn)行結(jié)果,當(dāng)前任務(wù)時(shí)間【" + time + "毫秒】"; } }

ExecutorService、Callable、Future 實(shí)際上都是屬于 Executor 框架。線程池支持有返回結(jié)果和無(wú)返回結(jié)果的任務(wù),有返回值的任務(wù)必須實(shí)現(xiàn)Callable接口,無(wú)返回值的任務(wù)必須實(shí)現(xiàn)Runnable接口。對(duì)于有結(jié)果的任務(wù),執(zhí)行 Callable 任務(wù)后,可以獲取一個(gè) Future 的對(duì)象,在該對(duì)象上調(diào)用 get 就可以獲取到Callable任務(wù)返回的 Object 了,但需要注意的是:get方法是阻塞的,如果線程未返回結(jié)果,那么 get() 方法會(huì)一直等待,直到有結(jié)果返回或者超時(shí)。

有關(guān)線程池以及?Executor 框架的內(nèi)容,可以閱讀這篇文章:https://blog.csdn.net/a745233700/article/details/109410376

參考文章:https://blog.csdn.net/u011480603/article/details/75332435

總結(jié)

以上是生活随笔為你收集整理的JUC多线程:创建线程的四种方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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