java多線程建立-Thread,Runnable,callable和threadpool

來源:互聯網
上載者:User

標籤:catch   this   min   turn   comm   簡單   art   解決   java多線程   

java建立多線程的方式有許多種,這裡簡要做個梳理

1. 繼承Thread類
繼承java.lang.Thread類,建立本地多線程的類,重載run()方法,調用Thread的方法啟動線程。範例程式碼如下:

MyThread.java

public class MyThread extends Thread {    public void run(){        private int copy = 0;        System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());        System.out.println("Thread serialnum:" + ++copy);        try {            sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());    }    public static void main(String[] args){        MyThread mt1 = new MyThread();        MyThread mt2 = new MyThread();        MyThread mt3 = new MyThread();        System.out.println("Start all Threads:");        mt1.start();        mt2.start();        mt3.start();    }}

輸出結果:

Start all Threads:Thread id:Thread-0 == print time:1495975884383Thread serialnum:1Thread id:Thread-1 == print time:1495975884383Thread serialnum:1Thread id:Thread-2 == print time:1495975884383Thread serialnum:1Thread id:Thread-1 == print time:1495975885385Thread id:Thread-0 == print time:1495975885385Thread id:Thread-2 == print time:1495975885385

2. 實現Runnable介面

實現java.lang.Runnable介面的run方法,使用實現的對象執行個體化Thread類,調用Thread對象的start()方法。
範例程式碼:

public class MyRunnable implements Runnable {    private int copy = 0;    public void run(){        System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());        System.out.println("Thread serialnum:" + ++copy);        try {            sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());    }    public static void main(String[] args){        MyRunnable mr = new MyRunnable();        System.out.println("Start all Threads:");        new Thread(mr).start();        new Thread(mr).start();        new Thread(mr).start();    }}

輸出結果:

Start all Threads:Thread id:Thread-0 == print time:1495975833588Thread id:Thread-1 == print time:1495975833588Thread serial:1Thread id:Thread-2 == print time:1495975833588Thread serial:2Thread serial:3Thread id:Thread-0 == print time:1495975834603Thread id:Thread-1 == print time:1495975834603Thread id:Thread-2 == print time:1495975834603

對比Thread方法和Runnable方法的使輸出結果不難發現:
. 二者均可實現多線程並發效果
. Runnable的方法可以使用一個Runnable對象建立多個線程,這多個線程共用其依賴的Runnable對象的資源,適用於多個線程處理相同資源的情境(網上舉得較多的例子:賣票);Thread的方法則是完全相互獨立的線程

事實上,嫌貴而言,當前Runnable使用的要比Thread方法普遍的多,除了上面說的資源共用的原因之外,Java的單繼承特性也增大了Thread方法的局限性。

3. 實現Callable介面
相對於上述繼承Thread類的方法和實現Runnable介面的方法,實現Callable介面的方法不但可以可以實現多線程並發,還能夠處理線程的傳回值或者擷取執行異常。使用Callable實現多線程編程需要實現Callable的call方法(在call方法中指定傳回值,拋出異常),構造與之關聯的FutureTask對象,啟動線程後,線程執行的結果會儲存在FutureTask對象中,可以使用FutureTask的get方法擷取。範例程式碼:

import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;import static java.lang.Thread.sleep;public class MyCallable implements Callable<Integer> {    private int flag = 0;    public Integer call() throws Exception {        System.out.println("Thread id:" + Thread.currentThread().getName() + "  == print time:"+System.currentTimeMillis());        sleep(10000);        System.out.println("Thread id:" + Thread.currentThread().getName() + "  == print time:"+System.currentTimeMillis());        ++flag;        return flag;    }    public static void main(String[] args) throws Exception{        MyCallable myCallable = new MyCallable();        FutureTask<Integer> future = new FutureTask<Integer>(myCallable);        FutureTask<Integer> future2 = new FutureTask<Integer>(myCallable);        new Thread(future).start();        new Thread(future2).start();        int Result,Result2;//        while (!future.isDone());        Result = future.get();////        while(!future2.isDone());        Result2 = future2.get();        System.out.println("GET THREAD NAME:"+ Result );        System.out.println("GET THREAD NAME 2:"+Result2);    }}

執行結果:

Thread id:Thread-0  == print time:1495997744617Thread id:Thread-1  == print time:1495997744617Thread id:Thread-0  == print time:1495997754625Thread id:Thread-1  == print time:1495997754625GET THREAD NAME:1GET THREAD NAME 2:2

 

上述代碼執行邏輯與前面Runnale的範例程式碼類似,通過構造Thread對象來啟動多線程。區別在於此處構造了futureTask方法用來用來儲存線程傳回值。需要注意的是,線程的Callable泛型介面裡的類型和call()方法的傳回值類型和FutureTask的泛型介面類型要一致。

4. 使用線程池和Executor架構
前面的三種方案,我們建立了Runnable或者Callable或者Thread的任務,扔到Thread中去啟動,我們需要手動去管理各種多線程的參數,比如線程數量,線程複用,安全執行緒的控制等。Java5以後的版本提供了Executor技術,能夠提供搭建好的線程池,為多線程提供了完整的解決方案,能夠有效管理線程數量,線程複用策略,保證安全執行緒,避免this逃逸問題等。
Executor提供的線程池方案包括newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool和SingleThreadExecutor(Fork/Join架構還提供了一個newWorkStealingPool),這些線程池分別提供了不同的線程管理方案,執行返回一個ExecutorService對象,這個對象可以調用execute()方法或者submit()方法,將前面定義的Runnable任務或者Callable任務或者Thread任務提交到各個線程去執行

我們以比較常用的newCachedThreadPool()為例,下面範例程式碼使用ExecutorService執行一個Callable對象任務,擷取每個線程的傳回值。

import java.util.ArrayList;import java.util.List;import java.util.concurrent.*;import static java.lang.Thread.sleep;public class MyCallable2 implements Callable<String> {    public String call() throws Exception{        sleep(1000);        System.out.println("terminate the thread : "+Thread.currentThread().getName());        return Thread.currentThread().getName();    }    public static void main(String[] args){        ExecutorService es = Executors.newCachedThreadPool();        List<Future<String>> futureList = new ArrayList<Future<String>>();        for(int i=0;i<5;i++){            Future future = es.submit(new MyCallable2());            futureList.add(future);        }        for (Future f: futureList             ) {            while(!f.isDone());            try {                System.out.println("EXECUTE RESULT:"+f.get());            } catch (InterruptedException e) {                e.printStackTrace();            } catch (ExecutionException e) {                e.printStackTrace();            }            finally {                es.shutdown();            }        }    }}

執行結果如下:

terminate the thread : pool-1-thread-5terminate the thread : pool-1-thread-4terminate the thread : pool-1-thread-3terminate the thread : pool-1-thread-2terminate the thread : pool-1-thread-1EXECUTE RESULT:pool-1-thread-1EXECUTE RESULT:pool-1-thread-2EXECUTE RESULT:pool-1-thread-3EXECUTE RESULT:pool-1-thread-4EXECUTE RESULT:pool-1-thread-5

使用Executors建立Runnable線程與建立Callable線程的方法類似,且不用管理傳回值,相對更加簡單,此處不再贅述。

java多線程建立-Thread,Runnable,callable和threadpool

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.