在Java中,創建線程有以下幾種方式:
通過實現 Runnable 接口;
通過繼承 Thread 類本身;
通過 Callable 和 Future 創建線程。
通過實現 Runnable 接口來創建線程
創建線程最簡單的方式就是直接實現Runnable接口,該接口定義了一個run()方法,在我們的實現類中通過對該方法的實現來定義我們自己的任務,這樣使得我們在創建並啓動線程之後能夠執行我們自己的任務。比如我們要執行一個倒計時的任務,我們就可以像下面的代碼一樣實現:
public class RunnableDemo implements Runnable {
@Override
public void run() {
System.out.println("倒計時開始:");
for(int i = 0; i < 10 ; i++){
System.out.println(10-i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread thread = new Thread(new RunnableDemo(),"Runnable-Thread");
thread.start();
}
}
通過繼承Thread來創建線程
創建一個線程的第二種方法是創建一個新的類,該類繼承 Thread 類(關於Thread類我們會在後續的文章中詳細闡述),然後創建一個該類的實例。
繼承類必須重寫 run() 方法,該方法是新線程的入口點。它也必須調用 start() 方法才能執行。
該方法儘管被列爲一種多線程實現方式,但是本質上也是實現了 Runnable 接口的一個實例。
通過繼承Thread重寫上面的倒計時任務如下:
public class ThreadDemo extends Thread {
public void run() {
System.out.println("倒計時開始:");
for(int i = 0; i < 10 ; i++){
System.out.println(10-i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadDemo thread = new ThreadDemo();
thread.start();
}
}
通過 Callable 和 Future 創建線程
Runnable是執行工作的獨立任務,但是他不返回任何值,如果你希望任務在完成時能夠返回一個值,那麼可以實現Callable接口來實現。Callable接口是一種具有類型參數的泛型接口,通過查看它的源碼我們可以發現,它的類型參數所表示的是從call()中返回的值的類型。Callable類型的任務可以有兩種執行方式:
藉助FutureTask執行
藉助Executor來運執行
藉助FutureTask執行
創建 Callable 接口的實現類,並實現 call() 方法,該 call() 方法將作爲線程執行體,並且有返回值。
創建 Callable 實現類的實例,使用 FutureTask 類來包裝 Callable 對象,該 FutureTask 對象封裝了該 Callable 對象的 call() 方法的返回值。
使用 FutureTask 對象作爲 Thread 對象的 target 創建並啓動新線程。
調用 FutureTask 對象的 get() 方法來獲得子線程執行結束後的返回值。
public class CallableThreadDemo implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("線程在進行計算");
Thread.sleep(1000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<Integer> mycallabletask = new CallableThreadDemo();
FutureTask<Integer> futuretask= new FutureTask<Integer>(mycallabletask);
new Thread(futuretask).start();
System.out.println("返回值:"+futuretask.get());
}
}
藉助Executor來運執行
藉助Executor必須使用ExecutorService.submit()方法調用它,下面是對上一個實例的改造:
public class CallableThreadDemo2 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("線程在進行計算");
Thread.sleep(1000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService exec = Executors.newCachedThreadPool();
Future<Integer> future = exec.submit(new CallableThreadDemo2());
System.out.println("返回值:"+ future.get());
exec.shutdown();
}
}
三種方式對比
採用實現 Runnable、Callable 接口的方式創建多線程時,線程類只是實現了 Runnable 接口或 Callable 接口,還可以繼承其他類。
使用繼承 Thread 類的方式創建多線程時,編寫簡單,如果需要訪問當前線程,則無需使用 Thread.currentThread() 方法,直接使用 this 即可獲得當前線程。
參考:
http://www.runoob.com/java/java-multithreading.html
《java編程思想》