Java 創建線程三種方式
Java使用Thread類代表線程,所有的線程對象都必須是Thread類或其子類的實例。Java可以用三種方式來創建線程
(1)繼承Thread類創建線程
(2)實現Runnable接口創建線程
(3)使用Callable和Future創建線程
1、繼承Thread類創建線程
創建此類線程一般需要以下三步:
(1)定義Thread類的子類,並重寫該類的run()方法,該方法的方法體就是線程需要完成的任務,run()方法也稱爲線程執行體。
(2)創建Thread子類的實例,也就是創建了線程對象
(3)啓動線程,即調用線程的start()方法
實例:
package Thread;
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("MyThread 線程啓動成功!");
}
public static void main(String args[]){
//創建線程對象
MyThread myThread = new MyThread();
//啓動線程
myThread.start();
}
}
運行結果:
MyThread 線程啓動成功!
2、實現Runnable接口創建線程
一般三個步驟:
(1)定義Runnable接口的實現類,一樣要重寫run()方法,這個run()方法和Thread中的run()方法一樣是線程的執行體
(2)創建Runnable實現類的實例,並用這個實例作爲Thread的target來創建Thread對象,這個Thread對象纔是真正的線程對象
(3)通過調用線程對象的start()方法來啓動線程
實例:
package Thread;
//實現Runnable 接口,並重寫run()方法
public class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println("MyThread2 線程啓動成功!");
}
public static void main(String args[]){
//創建線程實例
Thread thread = new Thread(new MyThread2());
//啓動線程
thread.start();
}
}
運行結果:
MyThread2 線程啓動成功!
3、使用Callable和Future創建線程
(1)先來了解一下Callable 接口
Callable是類似於Runnable的接口,實現Callable接口的類和實現Runnable的類都是可被其他線程執行的任務。Callable接口的定義如下:
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
Callable的類型參數是返回值的類型。例如:
Callable<Integer>表示一個最終返回Integer對象的異步計算。
(2)Future保存異步計算的結果。實際應用中可以啓動一個計算,將Future對象交給某個線程,然後執行其他操作。Future對象的所有者在結果計算好之後就可以獲得它。Future接口具有下面的方法:
public interface Future<V> {
//可以用cancel方法取消該計算。如果計算還沒有開始,它被取消且不再開始。
//如果計算處於運行之中,那麼如果mayInterrupt參數爲true,它就被中斷
boolean cancel(boolean mayInterruptIfRunning);
//判斷是夠被取消
boolean isCancelled();
//如果計算還在進行,isDone方法返回false;如果完成了,則返回true。
boolean isDone();
//調用被阻塞,直到計算完成
V get() throws InterruptedException, ExecutionException;
//設置等待時間,get方法的調用超時,拋出一個TimeoutException異常
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
(3) FutureTask包裝器是一種非常便利的機制,同時實現了Future和Runnable接口。FutureTask有2個構造方法
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
創建線程的步驟一般如下:
(1)創建Callable接口的實現類,並實現call()方法,然後創建該實現類的實例;
(2)使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了Callable對象的call()方法的返回值
(3)使用FutureTask對象作爲Thread對象的target創建並啓動線程(因爲FutureTask實現了Runnable接口)
(4)調用FutureTask對象的get()方法來獲得子線程執行結束後的返回值。
public class Thread3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> future = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("線程啓動成功!");
return 1;
}
});
new Thread(future).start();
System.out.println("或得線程返回值爲:" + future.get());
}
}
結果:
線程啓動成功!
或得線程返回值爲:1
4、總結
(1)實現Runnable和實現Callable接口的方式基本相同,不過是後者執行call()方法有返回值,後者線程執行體run()方法無返回值;
(2)基於Java單繼承的原因,推薦使用第二或第三種創建線程;