建立線程能夠說是併發知識中最基礎的操做了,JDK 提供的建立線程的方式,若是不包括經過線程池的話,目前有三種形式,它們分別是經過繼承 Thread 類,經過實現 Runable 接口,經過 FutureTask。以下圖所示多線程
下面整理了一下 3 種方法的具體使用與異同。併發
class MyThread extends Thread {
@Override
public void run() {
String threadName = getName();
for (int i = 0; i < 20; i++) {
System.out.println("線程[" + threadName + "]運行開始,i = " + i + " time = " + new Date());
}
}
}複製代碼
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
myThread1.start();
myThread2.start();
String threadName = Thread.currentThread().getName();
for (int i = 0; i < 20; i++) {
System.out.println("線程[" + threadName + "]運行開始,i = " + i + " time = " + new Date());
}複製代碼
總體流程以下:異步
這裏步驟比較簡單和清晰ide
class MyRunable implements Runnable {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
for (int i = 0; i < 20; i++) {
System.out.println("線程[" + threadName + "]運行開始,i = " + i + " time = " + new Date());
}
}
}複製代碼
MyRunable myRunable = new MyRunable();
new Thread(myRunable).start();
new Thread(myRunable).start();
String threadName = Thread.currentThread().getName();
for (int i = 0; i < 20; i++) {
System.out.println("線程[" + threadName + "]運行開始,i = " + i + " time = " + new Date());
}複製代碼
總體流程以下:svg
具體步驟以下:函數
class MyCallerTask implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("執行任務開始");
Thread.sleep(3000);
System.out.println("執行任務結束");
return "hello";
}
}複製代碼
// 建立異步任務
FutureTask<String> futureTask = new FutureTask<>(new MyCallerTask());
// 啓動線程
new Thread(futureTask).start();
System.out.println("其它操做");
try {
// 等待任務執行完,並得到任務執行完的結果
String result = futureTask.get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}複製代碼
總體流程以下:spa
具體步驟以下:線程
經過上述的演示代碼,能夠看出這 3 種方法,其實各有優缺點code
經過代碼量與邏輯能夠明顯感受出來,第一種直接繼承 Thread 最方便,而且其它兩種到最後,仍是要依賴建立 Thread 才能實現。因此從方便及難易程度來看,能夠獲得以下結論:![](http://static.coder4j.cn/yuque/latex/8815a238f7257e13ab9459d03677c3f2.svg#card=math&code=Thread%20%20%3E%20Runable%20%3E%20FutureTask&height=16&width=251)cdn
經過演示代碼能夠看出,只有第一種是經過繼承,其它兩種是經過實現接口的形式。咱們都知道 JAVA 是不容許多繼承,可是能夠多實現。因此若是使用了第一種方法,就沒法再繼承別的類了。另外第一種把線程與線程任務冗餘在了一塊兒,不利於後期的維護。因此能夠獲得以下結論:
從代碼中能夠很容易看出,只有經過 FutureTask 的方式纔有返回值,另外兩種均沒有,因此得出以下結論
若是要用到返回值,那不用想,確定只能使用 FutureTask 的方法。若是對於返回值沒有要求,那Thread 與 Runable 都可,不過,考慮到可擴展性,最好使用 Runable 的形式。不過,話說回來,若是在真正項目中使用,綜合考慮,通常仍是最推薦經過線程池去建立。