執行緒建立的四種方式
建立執行緒方式
方式一、建立一個任務類實現Runnable介面,並將其具體物件提交給Thread構造器
建立一個發射類LiftOff實現Runnable介面:
package concurrency; public class LiftOff implements Runnable { protected int countDown = 10; // Default private static int taskCount = 0; private final int id = taskCount++; public LiftOff() { } public LiftOff(int countDown) { this.countDown = countDown; } public String status() { return Thread.currentThread() + "#" + id + "(" + (countDown > 0 ? countDown : "Liftoff!") + "), "; } public void run() { while (countDown-- > 0) { System.out.println(status()); Thread.yield(); } } }
以上程式碼中呼叫了Thread.yield()方法,該方法的作用是建議執行緒排程器切換到其它執行緒執行任務,注意,只是建議,不保證採納;
建立完任務類之後,可以在Main函式中使用LiftOff物件建立一個Thread物件,並呼叫其start方法啟動該執行緒,如下:
package concurrency; public class BasicThreads { public static void main(String[] args) { Thread t = new Thread(new LiftOff()); t.start(); System.out.println(Thread.currentThread() + "Waiting for LiftOff"); } }
列印結果如下,注意該程式中是同時存在兩個執行緒(main和Thread-0)在執行的;
另外關於Thread物件的列印形式為[Thread-0,5,main],其中依次代表[執行緒名,執行緒優先順序、執行緒組名], 具體可檢視Thread類的toString方法;
Thread[main,5,main]Waiting for LiftOff Thread[Thread-0,5,main]#0(9), Thread[Thread-0,5,main]#0(8), Thread[Thread-0,5,main]#0(7), Thread[Thread-0,5,main]#0(6), Thread[Thread-0,5,main]#0(5), Thread[Thread-0,5,main]#0(4), Thread[Thread-0,5,main]#0(3), Thread[Thread-0,5,main]#0(2), Thread[Thread-0,5,main]#0(1), Thread[Thread-0,5,main]#0(Liftoff!),
方式二、繼承Thread類,呼叫其具體物件的start方法
package concurrency; public class SimpleThread extends Thread { private int countDown = 5; private static int threadCount = 0; public SimpleThread() { // Store the thread name: super(Integer.toString(++threadCount)); start(); } public String toString() { return "#" + getName() + "(" + countDown + "), "; } public void run() { while (true) { System.out.println(this); if (--countDown == 0) return; } } public static void main(String[] args) { for (int i = 0; i < 5; i++) new SimpleThread(); } }
對比通過實現Runnable介面的方式,該方式不建議使用,因為java的單繼承機制,通常通過實現介面比繼承會更好點;
另外還可以通過內部內部類將執行緒程式碼隱藏在類中,如下寫法;
class InnerThread1 { private int countDown = 5; private Inner inner; private class Inner extends Thread { Inner(String name) { super(name); start(); } public void run() { try { while (true) { print(this); if (--countDown == 0) return; sleep(10); } } catch (InterruptedException e) { print("interrupted"); } } public String toString() { return getName() + ": " + countDown; } } public InnerThread1(String name) { inner = new Inner(name); } }
方式三、建立一個任務類實現Runnable介面,並將其具體物件提交給Executors【推薦】
java.util.concurrent包中的執行器Executors可以幫助我們管理Thread物件,簡化併發程式設計,如下,可以使用Executors類中的newCachedThreadPool靜態方法建立一個可快取的執行緒池,並用其執行相關任務;
package concurrency; import java.util.concurrent.*; public class CachedThreadPool { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) exec.execute(new LiftOff()); exec.shutdown(); } }
在Executors類中,除了通過newCachedThreadPool建立執行緒池外,還可以建立通過以下方法建立其它種類的執行緒池:
newFixedThreadPool:固定大小度的執行緒池
newSingleThreadExecutor:單執行緒執行緒池
newScheduledThreadPool:執行定時和週期性任務
方式四、建立一個任務類實現Callable介面,並將其具體物件提交給Executors【推薦】
實現Callable介面的類同樣是一個任務類,與實現Runnable介面的區別是該方式可以有返回值;
在實現Callable介面的類中,執行緒執行的方法是call方法(有返回值),而不是run方法;
在main方法中可以通過呼叫ExecutorService的submit方法,返回一個Future物件,通過該物件可以獲取執行緒執行的返回值,注意需要等Future完成後才能取得結果,可以通過isDone方法來查詢Future是否已完成,或者直接呼叫get方法來獲取(會阻塞,直到結果準備就緒)。
package concurrency; import java.util.concurrent.*; import java.util.*; class TaskWithResult implements Callable<String> { private int id; public TaskWithResult(int id) { this.id = id; } public String call() { return "result of TaskWithResult " + id; } } public class CallableDemo { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); ArrayList<Future<String>> results = new ArrayList<Future<String>>(); for (int i = 0; i < 10; i++) results.add(exec.submit(new TaskWithResult(i))); for (Future<String> fs : results) try { System.out.println(fs.get()); } catch (InterruptedException e) { System.out.println(e); return; } catch (ExecutionException e) { System.out.println(e); } finally { exec.shutdown(); } } }
小結
其實,更普遍的,我覺得建立執行緒就兩種形式:
- 直接通過new Thread建立執行緒(可傳入任務物件);
- 建立任務物件提交給Executors去建立(其實內部的執行緒工廠也是通過new Thread建立);
另外,這裡的任務物件也有兩種方式建立,通過實現Runnable介面和實現Callable介面;
相關文章
- Java建立多執行緒的四種方式Java執行緒
- 建立執行緒的三種方式執行緒
- java執行緒建立的兩種方式Java執行緒
- 執行緒池建立的幾種方式執行緒
- 【java】【多執行緒】建立執行緒的兩種常用方式(2)Java執行緒
- C++ 執行緒同步的四種方式C++執行緒
- 執行緒池的五種狀態及建立執行緒池的幾種方式執行緒
- C++執行緒同步的四種方式(Windows)C++執行緒Windows
- jdk建立執行緒的方式JDK執行緒
- Java建立多執行緒的幾種方式實現Java執行緒
- Java 中執行緒池的7種建立方式!Java執行緒
- Java基礎:執行緒的三種建立方式Java執行緒
- java--執行緒池--建立執行緒池的幾種方式與執行緒池操作詳解Java執行緒
- Java併發(三)----建立執行緒的三種方式及檢視程式執行緒Java執行緒
- java的執行緒、建立執行緒的 3 種方式、靜態代理模式、Lambda表示式簡化執行緒Java執行緒模式
- 多執行緒的建立 兩種方式以及使用建議執行緒
- 併發程式設計 建立執行緒的三種方式程式設計執行緒
- 【Java】執行緒的建立方式Java執行緒
- 執行緒池建立方式執行緒
- 【併發技術01】傳統執行緒技術中建立執行緒的兩種方式執行緒
- 執行緒、開啟執行緒的兩種方式、執行緒下的Join方法、守護執行緒執行緒
- 建立執行緒的4種方法 and 執行緒的生命週期執行緒
- 幾種簡潔建立執行緒的方式以及使用注意事項執行緒
- 【Java基礎】:執行緒的三種建立方式對比分析Java執行緒
- 執行緒池以及四種常見執行緒池執行緒
- JDK提供的四種執行緒池JDK執行緒
- 常見的四種執行緒池執行緒
- java 四種執行緒池的使用Java執行緒
- Java四種執行緒池的使用Java執行緒
- java建立執行緒池的幾中方式Java執行緒
- 面試官問我:建立執行緒有幾種方式?我笑了面試執行緒
- EventBus四種執行緒交付模式執行緒模式
- 執行緒的建立方式以及synchronize的使用執行緒
- 執行緒介紹及建立方式執行緒
- Java併發基礎01:揭祕傳統執行緒技術中建立執行緒的兩種方式Java執行緒
- 【 Thread】建立執行緒的2種方法thread執行緒
- Java建立多執行緒的一種方法Java執行緒
- JAVA中執行緒建立的2種方法Java執行緒