1. 程式人生 > 實用技巧 >(一)執行緒建立與執行

(一)執行緒建立與執行

Java併發程式設計之美->讀書筆記

Java 中有3種執行緒建立方式,

1,分別為實現 Runnable 介面的 run 方法,

2,繼承 Thread並重寫 run 方法,

3,使用 FutureTask 方式 首先看繼承Thread類方式實現。

繼承Thread類並重寫run方法

    //繼承Thread類並重寫run方法
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("I am a children");
        }
    }

    public static void main(String[] args) {
        //建立執行緒
        MyThread myThread = new MyThread();
        //啟動執行緒
        myThread.start();
    }

如上程式碼中的MyThread類繼承了Thread類,並重寫了run()方法。

在main函式裡面建立了一個MyThread的例項,然後呼叫該例項的start方法啟動了執行緒。

需要注意的是,當建立完thread物件後該執行緒並沒有被啟動執行,知道呼叫了start方法後才真正啟動了執行緒。

其實呼叫start方法後執行緒並沒有馬上執行而是處於就緒狀態,這個就緒狀態是指該執行緒已經獲取了除CPU資源外的其他資源,等待獲取CPU資源後才會真正處於執行狀態。

一旦run方法執行完畢,該執行緒就處於終止狀態 * * 使用繼承方式的好處是,在run()方法內獲取當前執行緒直接使用this就可以了,無需使用Thread.currentThread()方法;

不好的地方是java不支援多繼承,如果繼承了Thread類,那麼就不能再繼承其他類。

另外任務與程式碼沒有分離,當多個執行緒執行一樣的任務時需要多份任務程式碼,而Runnable則沒有這個限制。

實現Runnable介面的run方法方式

    public static class RunnableTask implements Runnable{

        @Override
        public void run() {
            System.out.println("!222222");
        }
    }

    public static void main (String[] args){
        RunnableTask task = new RunnableTask();
        new Thread(task).start();
        new Thread(task).start();
    }

如上面程式碼所示,兩個執行緒共用一個task程式碼邏輯,如果需要,可以給RunnableTask新增引數進行任務區分。

另外,RunnableTask可以繼承其他類。但是上面介紹的兩種方式都有一個缺點,就是任務沒有返回值。

使用FutureTask的方式

 //建立任務類,類似Runnable
    public static class CallerTask implements Callable<String> {

        @Override
        public String call() throws Exception {
            return "hello";
        }
    }

    public static void main(String[] args) throws InterruptedException{
        //建立非同步任務
        Future<String> futureTask = new FutureTask<>(new CallerTask());
        //啟動執行緒
        new Thread((Runnable) futureTask).start();
        try {
            String result = futureTask.get();
            System.out.println(result);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

如上程式碼中的CallerTask類實現了Callable介面的call()方法。

在main函式內首先建立了一個FutrueTask物件(建構函式為CallerTask的例項),然後使用建立的FutrueTask物件作為任務建立了一個執行緒並且啟動它,

最後通過futureTask.get()等待任務執行完畢並返回結果

小結:使用繼承方式的好處是方便傳參,你可以在子類裡面新增成員變數,通過set方法設定引數或者通過建構函式進行傳遞,

而如果使用Runnable方式,則只能使用主執行緒裡面被宣告為final的變數。

不好的地方是java不支援多繼承,如果繼承了Thread類,那麼子類不能再繼承其他類,

而Runnable則沒有這個限制。前兩種方式都沒辦法拿到任務的返回結果,但是Futuretask方式可以.