Java多線程之建立線程的三種方式比較

一:繼承Thread類建立線程異步

        1:繼承Thread類定義線程子類;函數

        2:重寫run()方法,定義線程的操做;this

        3:經過建立的線程子類對象.start() 啓動線程。spa

複製代碼
package com.thread;   
public class FirstThreadTest extends Thread{   
    public void run()  
    {    
        System.out.println(Thread.currentThread().getName());  
    }  
    public static void main(String[] args)  
    {  
                new FirstThreadTest().start();    
    }  
  
} 
複製代碼

 

    二:實現Runnable接口建立線程線程

        1:實現Runnable接口定義線程類;對象

        2:重寫run()方法;繼承

        3:建立Thread對象:把上面 實現runnable接口的線程類 的對象做爲構造參數,建立出線程對象;接口

        4:由thread對象的start()方法啓動線程;資源

複製代碼
public class RunnableThreadTest implements Runnable  
{  
    public void run()  
    {     
            System.out.println(Thread.currentThread().getName())
    }  
    public static void main(String[] args)  
    {  
                new Thread(new RunnableThreadTest()).start();  
    }  
  
} 
複製代碼

 

    三:經過Callable接口和Future建立線程get

       1:建立Callable接口的實現類,並指明返回值類型;

       2:在實現類中重寫call()方法,並返回結果;

       3:建立Future<V>類型的list接收線程的預期結果: List<Future<String>> results = new ArrayList<Future<String>>();

       4:經過線程池啓動線程,而且把線程返回結果add到list中;

       5:遍歷list時,經過每一個元素的 get() 方法獲取每一個線程的實際運行結果值

複製代碼
//實現callable接口,定義線程類
class TaskWithResult implements Callable<String>{  
    private int id;  
    public TaskWithResult(int id){  
        this.id = id;  
    }  
   //重寫call()方法,切記拋出異常,並返回值
    public String call() throws Exception {  
        return "result of task:" + id;  
    }  
複製代碼
複製代碼
public class TestCallable {      
    public static void main(String[] args) {  
        //建立線程池
        ExecutorService es = Executors.newCachedThreadPool();
       //建立預期結果集合  
        List<Future<String>> results = new ArrayList<Future<String>>();  

        for(int i=0;i<5;i++){  
            //經過線程池啓動線程,把線程結果保存到預期結果集合
            results.add(es.submit(new TaskWithResult(i)));  
        }  
        //遍歷結果集合
        for(Future<String> fs : results){  
            try {  
                //經過 結果.get() 方法獲取每一個線程運行結束後的返回值。並處理異常
                System.out.println(fs.get());  
            } catch (InterruptedException | ExecutionException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
}  
複製代碼

另外一種啓動callable實現類線程的辦法:

複製代碼
Callable<Result> ca = new Callable<Result>() {
             public Result call() throws Exception {
                 System.out.println("當前線程名稱是:" + Thread.currentThread().getName());
                 Thread.sleep(2000L);
                return new Result("callable 執行完畢");
             }
         };
         //包裝對象
         FutureTask<Result> ft = new FutureTask<Result>(ca);
         try {            
          //啓動線程執行
            new Thread(ft).start();
            //獲取結果
             System.out.println(ft.get().getMsg());
          } catch (Exception e) {
             e.printStackTrace();
         }
     }
複製代碼

 

    四:對比

        1:繼承Thread類建立線程:其run()方法沒有返回值;經過start方法啓動;因爲Java不能容許多繼承,一個類若是須要繼承其餘類就不能再定義爲線程類了;run方法中的異常必須捕獲並處理;

        2:實現runnable接口建立線程:其run()方法沒有返回值;經過做爲thread類的構造函數的參數被包裝成thread類對象,再經過start方法啓動(由此,能夠同一個任務對象交給多個thread對象來運行,實現資源的共享以及並行處理);因爲接口能夠多實現,一個類能夠繼承其餘類的同時實現runnable接口成爲線程類;run方法中的異常必須捕獲並處理;

        3:實現Callable接口建立線程:其call()方法有返回值;通常經過線程池來啓動線程,也能夠先包裝成爲FutureTask對象,而後再由futuretask對象包裝成Thread對象經過start方法啓動;call()方法能夠拋出異常,直到在結果處經過get()方法獲取結果時再處理異常;在主線程啓動實現callable建立的線程時能夠得到一個Future對象做爲異步處理的預期結果,在經過future.get()方法時檢測啓動的線程是否已完成並返回結果,是則獲得結果,不然阻塞主線程等待任務線程完成並返回結果;

相關文章
相關標籤/搜索