1. 程式人生 > >詳解及對比建立執行緒的三種方式

詳解及對比建立執行緒的三種方式

一.Java建立執行緒的三種方式

Java中建立執行緒主要有三種方式:

1.繼承Thread類

2.實現Runnable介面

3.使用Callable和Future

1.繼承Thead類建立執行緒

(1)繼承Thread類並重寫run方法

(2)建立執行緒物件

(3)呼叫該執行緒物件的start()方法來啟動執行緒

public class CreateThreadTest {
 public static void main(String[] args) {
 new ThreadTest().start();
 new ThreadTest().start();
 }
}
class ThreadTest extends Thread{
 private int i = 0;
 @Override
 public void run() {
 for (; i < 100; i++) {
 System.out.println(Thread.currentThread().getName() + " is running: " + i);
 }
 }
}

2.實現Runnable介面建立執行緒

(1)定義一個類實現Runnable介面,並重寫該介面的run()方法

(2)建立 Runnable實現類的物件,作為建立Thread物件的target引數,此Thread物件才是真正的執行緒物件

(3)呼叫執行緒物件的start()方法來啟動執行緒

public class CreateThreadTest {
 public static void main(String[] args) {
 RunnableTest runnableTest = new RunnableTest();
 new Thread(runnableTest, "執行緒1").start();
 new Thread(runnableTest, "執行緒2").start();
 }
}
class RunnableTest implements Runnable{
 private int i = 0;
 @Override
 public void run() {
 for (; i < 100; i++) {
 System.out.println(Thread.currentThread().getName() + " is running: " + i);
 }
 }
}

3.使用Callable和Future建立執行緒

和Runnable介面不一樣,Callable介面提供了一個call()方法作為執行緒執行體,call()方法比run()方法功能要強大:call()方法可以有返回值,可以宣告丟擲異常。

public interface Callable<V> {
 V call() throws Exception;
}

Java5提供了Future介面來接收Callable介面中call()方法的返回值。 Callable介面是 Java5 新增的介面,不是Runnable介面的子介面,所以Callable物件不能直接作為Thread物件的target。針對這個問題,引入了RunnableFuture介面,RunnableFuture介面是Runnable介面和Future介面的子介面,可以作為Thread物件的target 。同時,Java5提供了一個RunnableFuture介面的實現類:FutureTask ,FutureTask可以作為Thread物件的target。

詳解及對比建立執行緒的三種方式

 

介紹了相關概念之後,使用Callable和Future建立執行緒的步驟如下:(1)定義一個類實現Callable介面,並重寫call()方法,該call()方法將作為執行緒執行體,並且有返回值

(2)建立Callable實現類的例項,使用FutureTask類來包裝Callable物件

(3)使用FutureTask物件作為Thread物件的target建立並啟動執行緒

(4)呼叫FutureTask物件的get()方法來獲得子執行緒執行結束後的返回值

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CreateThreadTest {
 public static void main(String[] args) {
 CallableTest callableTest = new CallableTest();
 FutureTask<Integer> futureTask = new FutureTask<>(callableTest);
 new Thread(futureTask).start();
 try {
 System.out.println("子執行緒的返回值: " + futureTask.get());
 } catch (InterruptedException e) {
 e.printStackTrace();
 } catch (ExecutionException e) {
 e.printStackTrace();
 }
 }
}
class CallableTest implements Callable{
 @Override
 public Integer call() throws Exception {
 int sum = 0;
 for (int i = 1; i < 101; i++) {
 sum += i;
 }
 System.out.println(Thread.currentThread().getName() + " is running: " + sum);
 return sum;
 }
}

二.建立執行緒的三種方式的對比

1.實現Runnable/Callable介面相比繼承Thread類的優勢

(1)適合多個執行緒進行資源共享

(2)可以避免java中單繼承的限制

(3)增加程式的健壯性,程式碼和資料獨立

(4)執行緒池只能放入Runable或Callable介面實現類,不能直接放入繼承Thread的類

2.Callable和Runnable的區別

(1) Callable重寫的是call()方法,Runnable重寫的方法是run()方法

(2) call()方法執行後可以有返回值,run()方法沒有返回值

(3) call()方法可以丟擲異常,run()方法不可以

(4) 執行Callable任務可以拿到一個Future物件,表示非同步計算的結果 。通過Future物件可以瞭解任務執行情況,可取消任務的執行,還可獲取執行結果

感謝你讀完了這篇文章

我是小架,我們

中秋節後見,祝