建立多線程可以使用下面四種方式:
- 繼承Thread
- 實作Runnable接口
- 通過Callable和FutureTask建立線程
- 通過線程池建立線程
第一印象, 你可能會想到這四種建立線程的方式. 可是其實建立線程隻有一種方式, 就是
new Thread()
展示上面所說的四種建立線程的方式:
代碼示範
package top.clearlight.blog.hollis.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CreateThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread().getName());
// 第一種建立方式
System.out.println("繼承Thread類建立的線程");
Thread t = new SubClassThread();
t.start();
// 第二種建立方式
System.out.println("實作Runnable接口建立線程");
CreateThread t2 = new CreateThread();
new Thread(t2).start();
// 第三種建立方式
CallableThread callableThread = new CallableThread();
FutureTask ft = new FutureTask(callableThread);
new Thread(ft).start();
// get()方法會阻塞主線程, 一直等子線程執行完成并傳回後才能繼續執行主線程後面的代碼
int i = 0;
// isDone判斷子線程是否執行完, call方法執行完後, 傳回true
while (!ft.isDone()) {
// 子線程執行完執行主線程執行其他事情
System.out.println("main" + i++);
Thread.sleep(1000);
}
System.out.println(ft.get());
System.out.println("阻塞了3s鐘後," + Thread.currentThread().getName() + "繼續執行");
}
}
class SubClassThread extends Thread {
@Override
public void run() {
System.out.println(getName());
}
}
class CallableThread implements Callable {
@Override
public Object call() throws Exception {
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
return "Hello Thread";
}
}
線程池建立線程代碼:
package top.clearlight.blog.hollis.thread;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CreateThreadPool {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
System.out.println("通過線程池建立線程");
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
/* threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});*/
// 通過線程池建立線程
threadPoolExecutor.execute(() -> System.out.println(Thread.currentThread().getName()));
}
}
首先, 多線程的狀态第一步, NEW(初始化) : 新建立一個線程對象, 但還沒調用start()方法.
下面開始講解為何建立線程的方式本質上隻有一種!
首先, 擴充Thread, 實際調用父類Thread類的無參構造函數,
進入調用四個參數的構造函數
繼續進入(部分代碼)
是以,
擴充Thread
方式其實是調用了Thread類的六個構造參數的構造方法來建立線程.
第二種方式 :
實作Runnable
, 通過實作Runnable接口後重寫run方法後建立Runnable對象傳入接受Runnable接口的構造參數
最終還是進入六個參數的構造函數, 隻是傳入的參數不同, 其實建立線程的方式, 本質都是通過傳入不同的參數來調用同一個構造函數.
第三種方式 :
這裡發現, 隻是傳入的target不同.
第四種方式 : 線程池建立線程
進入execute方法
/*
* 1.如果正在運作的線程少于corePoolSize線程,請嘗試執行以下操作:
*以給定指令作為第一個線程來啟動新線程
*任務。對addWorker的調用自動檢查runState和
* workerCount,是以可以防止假警報的增加
*在不應該執行的情況下通過傳回false進行線程化。
*
* 2.如果任務可以成功排隊,那麼我們仍然需要
*仔細檢查我們是否應該添加線程
*(因為現有的自上次檢查後死亡)或
*自從進入此方法以來,該池已關閉。是以我們
*重新檢查狀态,并在必要時回退排隊
*停止,如果沒有,則啟動一個新線程。
*
* 3.如果我們無法将任務排隊,那麼我們嘗試添加一個新的
*線程。如果失敗,我們知道我們已經關閉或飽和
*并是以拒絕任務。
* /
調用
addWorker