第一種: 通過繼承Thread類創建線程
第二種: 通過實現Runnable接口創建線程
這兩種早已爛記於心,這里就不作過多的介紹, 主要介紹其源碼
Thread類 implements Runnable
thread空線程的run方法 是判斷target是否存在實,再執行target實例中的run方法
public void run(){ if(this.target != null){ this.target.run(); } }
通過實現Runnable接口, 並且通過thread構造函數創建線程的方法
Runnable runnable = new Runnable(){...重寫run方法}; Thread thread_one = new Thread(runnable); Thread thread_two = new Thread(runnable);
如果創建多個線程, 實質是多個線程引用同一個target 實例
對比兩種方式的區別:
通過繼承Thread類實現多線程的方式由於單繼承的局限性, 不能再繼承其他類, 只能完成各自的任務
通過實現Runnable接口實現多線程的方式能更好的做到並發完成同一個任務, 因為訪問的是同一個target, 實現了共享數據
總之,在大多數情況下,都偏向於通過實現Runnable接口創建多線程
第三種: 使用Callable接口 和 FutureTask類創建線程
由於Thread類和Runnbale接口中的run方法沒有返回值, 所以這兩種方式不能獲取異步執行的結果
Callable接口
package java.util.concurrent; @FunctionalInterface public interface Callable<V>{ V call() throws Exception; }
@FunctionalInterface 注解標注在接口上, 表示此接口為"函數式接口"
函數式接口: 只有一個抽象方法的接口
此注解只是方便編譯器進行檢查, 不加也不會影響. 如果加了注解但該接口不是函數式接口,編譯器會報錯
Callable接口是泛型接口 ,也是函數式接口
call()抽象方法還有一個Exception的異常聲明, 容許方法內的異常直接拋出,並且可以不予捕獲
Future接口, RunnableFuture接口,以及FutureTask實現類都是位於 java.util.concurrent包下
V get() 用於阻塞性得到異步執行的結果. 此方法是阻塞性的,異步未執行完會處於阻塞狀態
Object outcome 用於保存call()方法的異步執行結果. get()會獲取
創建線程的具體步驟
class ReturnableTask implements Callable<Long>{ public long call() throws Exception{ //線程要執行的代碼 } } public static void main(String args[]) throws InterruptedException{ ReturnableTask task = new new ReturnableTask(); Futuretask<Long> FutureTask = new Futuretask<Long>(task); Thread thread = new Thread(FutureTask,"returnableThread"); thread.start(); System.out.println(FutureTask.get()); //得到異步執行結果 }
下圖為具體實現過程
兩個線程處於並發狀態, 默認異步執行
看起來兩個線程是同時進行,實質上是不是, 單個進程在同一時間只能執行一個進程,由於分給線程的時間片非常短(線程切換毫秒級),所以以為是同時
並發執行的消息通信機制分為同步和異步, 這些就不做過多解釋
總之,圖上的兩個線程不是同時運行
第四種: 通過線程池創建線程
通過Thread創建線程在執行完就被銷毀了, 不可服用. 在高並發場景中, 頻繁創建線程是非常消耗資源的, 通過線程池創建線程可以對已經創建好的線程進行復用
Executors 靜態工廠類 用於創建不同的線程池 java.util.concurrent;
//創建一個包含三個線程的線程池 private static ExecutorService pool = Executors.newFixedThreadPool(3);
Executor接口
void executo(Runnable command); //執行Runnable類型
ExecutorService<T> extends Executor
<T> Future<T> submit(Callable<T> task) //提交callable類型以執行
Future<?> submit(Runnable task) //提交Runnable類型以執行
具體實現
main Future future = pool.submit(new RuturnableTask()); Long result = (Long) future.get(); //得到異步執行的結果
execute() 與 submit() 執行線程方法的區別
execute()只能執行Runnable, 並且無返回值
submit() 既能執行Runnable又能執行callable, 並且有返回值
注: 實際生產環境中禁止使用Executors創建線程池