您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“Java中線程的創(chuàng)建方式是什么”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Java中線程的創(chuàng)建方式是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。
可以通過(guò)創(chuàng)建Thread的子類(lèi)并在子類(lèi)中重寫(xiě)run() 方法完成線程創(chuàng)建。示例如下所示。
public class ThreadTest { @Test public void 繼承Thread() throws Exception { // 創(chuàng)建線程對(duì)象 MyThread myThread = new MyThread(); // 啟動(dòng)線程 myThread.start(); // 睡1秒,等待子線程執(zhí)行完任務(wù) Thread.sleep(1000); } private static class MyThread extends Thread { @Override public void run() { System.out.println("線程執(zhí)行了"); } } }
運(yùn)行測(cè)試程序,打印如下。
其實(shí)可以只繼承Thread,而不重寫(xiě)run() 方法,此時(shí)是不會(huì)報(bào)錯(cuò)的,只不過(guò)調(diào)用start() 方法后線程不會(huì)執(zhí)行任何邏輯。示例如下。
public class ThreadTest { @Test public void 繼承Thread時(shí)可以不重寫(xiě)run方法() { // 創(chuàng)建沒(méi)有重寫(xiě)run()方法的線程對(duì)象 MyThreadNotOverrideRun myThread = new MyThreadNotOverrideRun(); // 啟動(dòng)線程,不報(bào)錯(cuò),執(zhí)行的是Thread的run()方法,無(wú)任何邏輯 myThread.start(); } private static class MyThreadNotOverrideRun extends Thread {} }
可以通過(guò)創(chuàng)建Runnable接口的實(shí)現(xiàn)類(lèi),然后將Runnable對(duì)象作為Thread對(duì)象的執(zhí)行任務(wù),來(lái)創(chuàng)建線程。示例如下。
public class ThreadTest { @Test public void 基于Runnable() throws Exception { // 創(chuàng)建Runnable任務(wù)對(duì)象 Runnable runnable = new Runnable() { @Override public void run() { System.out.println("任務(wù)執(zhí)行"); } }; // 創(chuàng)建Thread對(duì)象時(shí)將Runnable任務(wù)對(duì)象通過(guò)構(gòu)造函數(shù)傳入 Thread thread = new Thread(runnable); // 啟動(dòng)線程 thread.start(); // 睡1秒,等待子線程執(zhí)行完任務(wù) Thread.sleep(1000); } }
運(yùn)行測(cè)試程序,執(zhí)行結(jié)果如下所示。
Callable接口也是可以作為任務(wù)被線程執(zhí)行,其與Runnable接口的區(qū)別在于Callable任務(wù)可以有返回值,而Runnable任務(wù)沒(méi)有返回值。
由于Thread對(duì)象只能執(zhí)行Runnable任務(wù),因此無(wú)法直接讓Thread執(zhí)行Callable任務(wù),但是可以先將Callable封裝成FutureTask,而FutureTask是實(shí)現(xiàn)了Runnable接口的,所以Thread對(duì)象可以執(zhí)行FutureTask任務(wù)。示例如下。
public class ThreadTest { @Test public void 基于Callable() throws Exception { // 創(chuàng)建Callable任務(wù)對(duì)象 Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception { return "任務(wù)執(zhí)行結(jié)果"; } }; // 將Callable封裝成FutureTask FutureTask<String> futureTask = new FutureTask<>(callable); // 創(chuàng)建Thread對(duì)象時(shí)將FutureTask通過(guò)構(gòu)造函數(shù)傳入 Thread thread = new Thread(futureTask); // 啟動(dòng)線程 thread.start(); // 通過(guò)FutureTask拿到執(zhí)行結(jié)果 System.out.println(futureTask.get()); } }
運(yùn)行測(cè)試程序,結(jié)果如下。
在第三小節(jié)中是基于Callable來(lái)創(chuàng)建的FutureTask,本小節(jié)將基于Runnable來(lái)創(chuàng)建FutureTask。在此之前,先看一下FutureTask的類(lèi)圖,如下所示。
所以FutureTask即能夠作為Runnable被執(zhí)行,也能夠作為Future獲取異步執(zhí)行的結(jié)果。FutureTask有兩個(gè)構(gòu)造函數(shù),簽名如下。
// 基于Callable創(chuàng)建FutureTask public FutureTask(Callable<V> callable) // 基于Runnable創(chuàng)建FutureTask public FutureTask(Runnable runnable, V result)
下面重點(diǎn)看一下如何基于Runnable創(chuàng)建FutureTask,源碼如下所示。
public FutureTask(Runnable runnable, V result) { // 使用Executors工具類(lèi)將Runnable封裝成Callable this.callable = Executors.callable(runnable, result); this.state = NEW; }
繼續(xù)看Executors#callable(java.lang.Runnable, T) 方法,如下所示。
public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) { throw new NullPointerException(); } // 將Runnable封裝成RunnableAdapter return new RunnableAdapter<T>(task, result); }
那么Executors#callable(java.lang.Runnable, T) 方法中就是將Runnable封裝成了RunnableAdapter,最后再看一下RunnableAdapter的實(shí)現(xiàn)。
static final class RunnableAdapter<T> implements Callable<T> { final Runnable task; final T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T call() { // 執(zhí)行Runnable的邏輯 task.run(); // 執(zhí)行完畢后,result作為結(jié)果返回 return result; } }
所以這里可以知道,基于Runnable
創(chuàng)建FutureTask
,其本質(zhì)是將Runnable
先封裝為Callable
,然后再將Callable
封裝成FutureTask
。還有一點(diǎn)需要注意,在基于Runnable
創(chuàng)建FutureTask
時(shí),除了傳入Runnable
,還可以傳入一個(gè)作為返回結(jié)果的對(duì)象,Runnable
執(zhí)行完畢后,會(huì)將這個(gè)對(duì)象返回,這個(gè)對(duì)象也可以傳一個(gè)null,表示不需要返回值。
基于Runnable創(chuàng)建FutureTask的一個(gè)示例如下。
public class ThreadTest { @Test public void 基于Runnable來(lái)構(gòu)建FutureTask() throws Exception { // 創(chuàng)建結(jié)果對(duì)象 MyResult myResult = new MyResult(); // 創(chuàng)建Runnable任務(wù)對(duì)象 Runnable runnable = new Runnable() { @Override public void run() { myResult.setResult("任務(wù)執(zhí)行"); } }; // 將Runnable封裝成FutureTask // Runnable執(zhí)行后,會(huì)改變MyResult對(duì)象 FutureTask<MyResult> futureTask = new FutureTask<>(runnable, myResult); // 創(chuàng)建Thread對(duì)象時(shí)將FutureTask通過(guò)構(gòu)造函數(shù)傳入 Thread thread = new Thread(futureTask); // 啟動(dòng)線程 thread.start(); // 通過(guò)FutureTask拿到執(zhí)行結(jié)果 System.out.println(futureTask.get().getResult()); } private static class MyResult { String result; public MyResult() {} public MyResult(String result) { this.result = result; } public String getResult() { return result; } public void setResult(String result) { this.result = result; } } }
運(yùn)行測(cè)試程序,結(jié)果如下所示。
讀到這里,這篇“Java中線程的創(chuàng)建方式是什么”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。