Java 創建線程三種方式

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單繼承的原因,推薦使用第二或第三種創建線程;

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