java多線程、線程池的實現

mmp7 9年前發布 | 22K 次閱讀 Java開發 Java

Java實現多線程的3種方法:繼承Thread類、實現runnable接口、使用ExecutorService,Callable、Future實現有返回值的多線程。前2種線程的實現方式沒有返回值,第三種實現方式可以獲取線程執行的返回值。一:繼承java.lang.Thread類

    public class MyThread extends Thread {

    @Override  
    public void run() {  
        System.out.println( "my thread begin." );  
        try {  
            // 休眠1000毫秒  
            Thread.sleep( 1000 );  
        } catch ( InterruptedException e ) {  
            e.printStackTrace();  
        }  
        System.out.println( "my thread over." );  
    }  

    public static void main( String[] args ) {  
        MyThread thread = new MyThread();  
        thread.start();  
    }  
}  </pre><br />

二:實現java.lang.Runnable接口

    public class MyThread implements Runnable {  

        @Override  
        public void run() {  
            System.out.println( "my thread begin." );  
            try {  
                // 休眠1000毫秒  
                Thread.sleep( 1000 );  
                // do something...  
            } catch ( InterruptedException e ) {  
                e.printStackTrace();  
            }  
            System.out.println( "my thread over." );  
        }  

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

實現Runnable接口會比繼承Thread類更靈活一些,因為Java是單繼承,繼承了一個類就不能再繼承另外一個類,而接口可以實現多個。但是無論是繼承Thread類還是實現Runnable接口都不能獲取多線程的返回值,除非借助額外的變量,在run方法中修改一個變量,在其他地方使用這個變量,這種實現方式比較"雞肋"。

三:實現java.util.concurrent.Callable接口

    public class MyThread implements Callable<Object> {  

        @Override  
        public Object call() throws Exception {  
            System.out.println( "my thread begin." );  
            try {  
                // 休眠1000毫秒  
                Thread.sleep( 1000 );  
            } catch ( InterruptedException e ) {  
                e.printStackTrace();  
            }  
            System.out.println( "my thread over." );  
            return "ok";  
        }  

        public static void main( String[] args ) {  
            // 創建一個線程池  
            ExecutorService pool = Executors.newFixedThreadPool( 2 );  
            Future<Object> f = pool.submit( new MyThread() );  
            //關閉線程池  
            pool.shutdown();  
            try {  
                System.out.println( f.get() );  
            } catch ( InterruptedException e ) {  
                e.printStackTrace();  
            } catch ( ExecutionException e ) {  
                e.printStackTrace();  
            };  
        }  
    }  

通過創建一個線程池提交一個Callable任務就可以通過Future類來獲取線程的返回值了,調用Futureget()方法的時候,如果任務沒有完成則阻塞直到任務完成。正如get()的注釋:Waits if necessary for the computation to complete, and then retrieves its result.

面代碼中的ExecutorService接口繼承自Executor接口,Executor的實現基于生產者-消費者模式。提交任務的執行者是生產者(產生待完成的工作單元),執行任務的線程是消費者(消耗掉這些工作單元)。如果要實現一個生產者-消費者的設計,使用Executor通常是最簡單的方式。

Executors類提供了幾種創建線程池的方法,通過Exectors創建的線程池也實現了ExecutorService接口,方法如下:

1、固定大小的線程池:newFixedThreadPool(int nThreads)

創建固定大小的線程池。每次提交一個任務就創建一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那么線程池會補充一個新線程。

2、單任務線程池:Executors.newSingleThreadExecutor()

建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當于單線程串行執行所有任務。如果這個唯一的線程因為異常結束,那么會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行。

3、可變尺寸的線程池:Executors.newCachedThreadPool()

創建一個可緩存的線程池。如果線程池的大小超過了處理任務所需要的線程,那么就會回收部分空閑(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴于操作系統(或者說JVM)能夠創建的最大線程大小。

4、延遲線程池:Executors.newScheduledThreadPool(int corePoolSize)

創建一個大小無限的線程池。此線程池支持定時以及周期性執行任務的需求。

注意:shutdown()方法并不是終止線程的執行,而是禁止在這個Executor中添加新的任務。

 本文由用戶 mmp7 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!