1. 程式人生 > >java並發編程-----Executor線程池框架

java並發編程-----Executor線程池框架

rup 隊列 out 情況下 效率 tac 調用exe system wait

在Java 5之後,並發編程引入了一堆新的啟動、調度和管理線程的API。

Executor框架便是Java 5中引入的,

其內部使用了線程池機制,它在java.util.cocurrent 包下,通過該框架來控制線程的啟動、執行和關閉,可以簡化並發編程的操作。因此,在Java 5之後,通過Executor來啟動線程比使用Thread的start方法更好,除了更易管理,效率更好(用線程池實現,節約開銷)外,還有關鍵的一點:有助於避免this逃逸問題——如果我們在構造器中啟動一個線程,因為另一個任務可能會在構造器結束之前開始執行,此時可能會訪問到初始化了一半的對象用Executor在構造器中。

Executor框架包括:線程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。

Executors方法介紹

Executors工廠類

通過Executors提供四種線程池,newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool。

1.public static ExecutorService newFixedThreadPool(int nThreads)
創建固定數目線程的線程池。

2.public static ExecutorService newCachedThreadPool()
創建一個可緩存的線程池,調用execute將重用以前構造的線程(如果線程可用)。如果現有線程沒有可用的,則創建一個新線 程並添加到池中。終止並從緩存中移除那些已有 60 秒鐘未被使用的線程。

3.public static ExecutorService newSingleThreadExecutor()
創建一個單線程化的Executor。

4.public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

創建一個支持定時及周期性的任務執行的線程池,多數情況下可用來替代Timer類。

實例:

ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {
            Runnable syncRunnable = new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG, Thread.currentThread().getName());
                }
            };
            executorService.execute(syncRunnable);
        }

ExecutorService

ExecutorService是一個接口,ExecutorService接口繼承了Executor接口,定義了一些生命周期的方法。

public interface ExecutorService extends Executor {


    void shutdown();//順次地關閉ExecutorService,停止接收新的任務,等待所有已經提交的任務執行完畢之後,關閉ExecutorService


    List<Runnable> shutdownNow();//阻止等待任務啟動並試圖停止當前正在執行的任務,停止接收新的任務,返回處於等待的任務列表


    boolean isShutdown();//判斷線程池是否已經關閉

    boolean isTerminated();//如果關閉後所有任務都已完成,則返回 true。註意,除非首先調用 shutdown 或 shutdownNow,否則 isTerminated 永不為 true。


    boolean awaitTermination(long timeout, TimeUnit unit)//等待(阻塞)直到關閉或最長等待時間或發生中斷,timeout - 最長等待時間 ,unit - timeout 參數的時間單位  如果此執行程序終止,則返回 true;如果終止前超時期滿,則返回 false 


    <T> Future<T> submit(Callable<T> task);//提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future。該 Future 的 get 方法在成功完成時將會返回該任務的結果。


    <T> Future<T> submit(Runnable task, T result);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功完成時將會返回給定的結果。


    Future<?> submit(Runnable task);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功 完成時將會返回 null


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)//執行給定的任務,當所有任務完成時,返回保持任務狀態和結果的 Future 列表。返回列表的所有元素的 Future.isDone() 為 true。
        throws InterruptedException;


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)//執行給定的任務,當所有任務完成時,返回保持任務狀態和結果的 Future 列表。返回列表的所有元素的 Future.isDone() 為 true。
        throws InterruptedException;


    <T> T invokeAny(Collection<? extends Callable<T>> tasks)//執行給定的任務,如果在給定的超時期滿前某個任務已成功完成(也就是未拋出異常),則返回其結果。一旦正常或異常返回後,則取消尚未完成的任務。
        throws InterruptedException, ExecutionException;


    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

  

ExecutorService接口繼承自Executor接口,它提供了更豐富的實現多線程的方法,比如,ExecutorService提供了關閉自己的方法,以及可為跟蹤一個或多個異步任務執行狀況而生成 Future 的方法。 可以調用ExecutorService的shutdown()方法來平滑地關閉 ExecutorService,調用該方法後,將導致ExecutorService停止接受任何新的任務且等待已經提交的任務執行完成(已經提交的任務會分兩類:一類是已經在執行的,另一類是還沒有開始執行的),當所有已經提交的任務執行完畢後將會關閉ExecutorService。因此我們一般用該接口來實現和管理多線程。

ExecutorService的生命周期包括三種狀態:運行、關閉、終止。創建後便進入運行狀態,當調用了shutdown()方法時,便進入關閉狀態,此時意味著ExecutorService不再接受新的任務,但它還在執行已經提交了的任務,當素有已經提交了的任務執行完後,便到達終止狀態。如果不調用shutdown()方法,ExecutorService會一直處在運行狀態,不斷接收新的任務,執行新的任務,服務器端一般不需要關閉它,保持一直運行即可。

Executor執行Runnable任務

一旦Runnable任務傳遞到execute()方法,該方法便會自動在一個線程上執行。下面是是Executor執行Runnable任務的示例代碼:

public class TestCachedThreadPool{   
    public static void main(String[] args){   
        ExecutorService executorService = Executors.newCachedThreadPool();   
//      ExecutorService executorService = Executors.newFixedThreadPool(5);  
//      ExecutorService executorService = Executors.newSingleThreadExecutor();  
        for (int i = 0; i < 5; i++){   
            executorService.execute(new TestRunnable());   
            System.out.println("************* a" + i + " *************");   
        }   
        executorService.shutdown();   
    }   
}   

class TestRunnable implements Runnable{   
    public void run(){   
        System.out.println(Thread.currentThread().getName() + "線程被調用了。");   
    }   
}  

Executor執行Callable任務

在Java 5之後,任務分兩類:一類是實現了Runnable接口的類,一類是實現了Callable接口的類。兩者都可以被ExecutorService執行,但是Runnable任務沒有返回值,而Callable任務有返回值。並且Callable的call()方法只能通過ExecutorService的submit(Callable task) 方法來執行,並且返回一個 Future,是表示任務等待完成的 Future。

實例:

public class CallableDemo{   
    public static void main(String[] args){   
        ExecutorService executorService = Executors.newCachedThreadPool();   
        List<Future<String>> resultList = new ArrayList<Future<String>>();   

        //創建10個任務並執行   
        for (int i = 0; i < 10; i++){   
            //使用ExecutorService執行Callable類型的任務,並將結果保存在future變量中   
            Future<String> future = executorService.submit(new TaskWithResult(i));   
            //將任務執行結果存儲到List中   
            resultList.add(future);   
        }   

        //遍歷任務的結果   
        for (Future<String> fs : resultList){   
                try{   
                    while(!fs.isDone);//Future返回如果沒有完成,則一直循環等待,直到Future返回完成  
                    System.out.println(fs.get());     //打印各個線程(任務)執行的結果   
                }catch(InterruptedException e){   
                    e.printStackTrace();   
                }catch(ExecutionException e){   
                    e.printStackTrace();   
                }finally{   
                    //啟動一次順序關閉,執行以前提交的任務,但不接受新任務  
                    executorService.shutdown();   
                }   
        }   
    }   
}   


class TaskWithResult implements Callable<String>{   
    private int id;   

    public TaskWithResult(int id){   
        this.id = id;   
    }   

    /**  
     * 任務的具體過程,一旦任務傳給ExecutorService的submit方法, 
     * 則該方法自動在一個線程上執行 
     */   
    public String call() throws Exception {  
        System.out.println("call()方法被自動調用!!!    " + Thread.currentThread().getName());   
        //該返回結果將被Future的get方法得到  
        return "call()方法被自動調用,任務返回的結果是:" + id + "    " + Thread.currentThread().getName();   
    }   
}  

自定義線程池

自定義線程池,可以用ThreadPoolExecutor類創建,它有多個構造方法來創建線程池,用該類很容易實現自定義的線程池,這裏先貼上示例程序:

public class ThreadPoolTest{   
    public static void main(String[] args){   
        //創建等待隊列   
        BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20);   
        //創建線程池,池中保存的線程數為3,允許的最大線程數為5  
        ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,50,TimeUnit.MILLISECONDS,bqueue);   
        //創建七個任務   
        Runnable t1 = new MyThread();   
        Runnable t2 = new MyThread();   
        Runnable t3 = new MyThread();   
        Runnable t4 = new MyThread();   
        Runnable t5 = new MyThread();   
        Runnable t6 = new MyThread();   
        Runnable t7 = new MyThread();   
        //每個任務會在一個線程上執行  
        pool.execute(t1);   
        pool.execute(t2);   
        pool.execute(t3);   
        pool.execute(t4);   
        pool.execute(t5);   
        pool.execute(t6);   
        pool.execute(t7);   
        //關閉線程池   
        pool.shutdown();   
    }   
}   

class MyThread implements Runnable{   
    @Override   
    public void run(){   
        System.out.println(Thread.currentThread().getName() + "正在執行。。。");   
        try{   
            Thread.sleep(100);   
        }catch(InterruptedException e){   
            e.printStackTrace();   
        }   
    }   
}  

  

  

  

java並發編程-----Executor線程池框架