Java多線程編程——線程創建方式

在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編程思想》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章