1. 程式人生 > >java多執行緒之建立執行緒的三種方式優缺點

java多執行緒之建立執行緒的三種方式優缺點

Java使用Thread類代表執行緒,所有的執行緒物件都必須是Thread類或其子類的例項。 
一、繼承Thread類建立執行緒類 
1.重寫run方法。該run()方法的方法體就代表了執行緒需要完成的任務。 
2.建立Thread子類的例項。 
3.呼叫執行緒物件的start()方法來啟動該執行緒。

public class TestCode1 extends Thread
{
    private int i;
    public void run()
    {
        for(;i<100;i++)
        {
            System.out.println(getName()+" "+i);
        }
    }


    public static void main(String[] args) 
    {
        for(int i=0;i<100;i++)
        {
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i==20){
                new TestCode1().start();
                new TestCode1().start();
            }
        }
    }
}

二、實現Runnable介面建立執行緒類 
1.定義Runnable的實現類,重寫run()方法。 
2.建立Runnable實現類的例項,並以此作為Thread的target來建立物件,該物件才是真正的執行緒物件。

public class TestCode2 implements Runnable
{
    private int i;
    public void run()
    {
        for(;i<100;i++)
        {
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
    }


    public static void main(String[] args) 
    {
        for(int i=0;i<100;i++)
        {
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i==20){
                TestCode2 test=new TestCode2();
                new Thread(test,"新執行緒1").start();
                new Thread(test,"新執行緒2").start();
            }
        }
    }
}

三、使用Callable和Future建立執行緒 
1.建立Callable介面的實現類,並實現Call()方法,該方法將作為執行緒執行體,且該方法有返回值,再建立Callable實現類的例項。從Java8開始,可以直接使用Lambda表示式建立Callable物件。 
2.使用FutureTask來包裝Callable物件,該FutureTask物件封裝了該Callable物件的call方法的返回值。 
3.使用FutureTask物件作為Thread物件的target建立並啟動新執行緒。 
4.呼叫FutureTask物件的get()方法來獲取子執行緒執行結束後的返回值。

public class TestCode3 {
    public static void main(String[] args) {
        TestCode3 test = new TestCode3();
        FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)()->{
            int i=0;
            for(;i<100;i++){
                System.out.println(Thread.currentThread().getName()+"迴圈變數i的值:"+i);
            }
            return i;
        });
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"迴圈變數i的值:"+i);
            if(i==20){
                new Thread(task,"有返回值的執行緒").start();
            }
            try{
                System.out.println("子執行緒的返回值:"+task.get());
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

四、淺談三種方式優劣勢 
    通過繼承Thread類或實現Runnable、Callable介面都可以實現多執行緒,不過實現Runnable介面與實現Callable介面的方式基本相同,只是Callable接口裡定義的方法有返回值,可以宣告丟擲異常而已。因此可以將實現Runnable介面和實現Callable介面歸為一種方式。這種方式與繼承Thread方式之間的主要差別如下。 
    1.採用實現Runnable、Callable介面的方式建立多執行緒的優缺點: 
優勢:(1)執行緒類只是實現了Runnable介面與Callable介面,還可以繼承其他類。 
           (2)在這種方式下,多個執行緒可以共享一個target物件,所以非常適合多個相同執行緒來處理同一份資源的情況,從而可以將CPU、程式碼和資料分開,形成清晰的模型,較好地體現了面向物件的思想。 
劣勢:程式設計稍稍複雜,如果需要訪問當前執行緒,則必須使用Thread.currentThread()方法。 
    2.採用繼承Thread類的方法建立多執行緒的優缺點: 
劣勢:因為執行緒類已經繼承了Thread類,所以不能再繼承其他父類。 
優勢:編寫簡單,如果需要訪問當前執行緒,則無須使用Thread.currentThread()方法,直接使用this即可獲得當前執行緒。 
五、總結 
    鑑於上面分析,因此一般推薦採用實現Runnable介面、Callable介面的方式來建立多執行緒。