併發編程——關於任務的執行(Task Execution)

1.多線程套接字編程中的不足
記得之前做過學校的一個實驗,是關於多線程套接字編程地,在那次實驗中,我們採用瞭如下的代碼:

ServerSocket server = new ServerSocket(80);
while(true){
    //新建線程
    new  Thread(xxx).start;
    }

在上方代碼,我們爲了提升服務器的效率,我們使用了多線程編程,但是同時,這個代碼,他也是會無限制創建線程地,他的不足主要有:
1.線程每次創建和銷燬的代價非常高;2.對內存的消耗很大,可運行的線程數量很可能多於處理器數量;3.穩定性,如果線程超過了當前虛擬機或者操作系統的限制,那很可能拋出異常。

針對這種代碼,我們給出了更好的解決方案,就是使用線程池。

2.1關於Executor框架和線程池
Excetor是一個接口,它裏面就是一個execute方法,參數是Runnable類型,作用就是執行這個實現了Runable接口的類的線程。很簡單,但是爲靈活且強大的線程池(異步執行框架)提供了基礎。

關於線程池的使用:

類A {
    private static final Exceutor exex = Executors.newFixedThreadPool(100);

    public static void main(String[] args)throws IOException{
        ServerSocket socket = new ServerSocket(80);
        Runnable task = new B//某個實現了Runnable的類
        exec.execute(task);
    }
}

關於線程池的優勢:1.可以寵用現有線程,而不用創建新線程,節省開銷;2.可以限定線程池大小,創建足夠多的線程讓系統保持忙碌,卻不會耗盡資源使任務失敗。
類庫提供了一些Executors靜態工廠方法來創建一個線程池:
1.newFixedThreadPool。 創建一個固定長度的線程池
2.newCachedThreadPool。 創建一個可緩存的線程池,如果線程池的當前規模超過了處理需求時,那麼將回收空閒的線程,而當需求增加時則可以添加新的線程,線程池的規模不存在任何限制。
3.newSingleThreadExecutor。這是一個單線程的線程池,他創建單個工作者線程來執行任務,如果這個線程異常結束,會創建另一個線程來代替。
4.newScheduledThreadPool。創建了一個固定長度的現車公尺,而且一延時或定時的方式來執行任務,類似Timer定時器。

newFixedThreadPool和newCachedThreadPool這兩個工廠方法返回通用的ThreadPoolExecutor實例,可以直接用來構造專門用途的exxecutor

2.2線程池的生命週期
ExecutorService 拓展了Executor接口,新增了關於結束線程池生命的方法,就是說,我們可以用ExecutorService接口,就可以承接真是的線程池實例類了。
主要方法有shutdown()//正常、安全、緩慢關閉; 還有shutdownnow//強行快速關閉線程池

2.3線程池和攜帶結果的任務,Callable和Future
Runnable是一種有侷限的抽象,run,它並不能返回一個值。所以我們有了Callable接口,他認爲主入口點(call方法)將返回一個值,並可能拋出一個異常。
Future表示一個任務的生命週期,並提供方法來判斷是否完成或者取消,獲取任務結果,他隱含了一個含義,任務的生命週期只能前進,不能後退。他也是一個接口。
get方法取決於任務狀態,如果任務還沒完成就會阻塞。
關於Future和Callable的使用例子,使用Future等待圖像下載:

class FutureRenderer {  
    private final ExecutorService executor = .;  

    void renderPage(CharSequence source) {  
        final List<ImageInfo> imageInfos = scanForImageInfo(source);  
        Callable<List<ImageData>> task = new Callable<List<ImageData>> () {  
            public List<ImageData> call() {  
                List<ImageData> result = new ArrayList<ImageData>();  
                for(ImageInfo imageInfo : imageInfos) {  
                    result.add(imageInfo.downloadImage());  
                }  
                return result;  
            }  
        };  

        Future<List<ImageData>> future = executor.submit(task);  
        renderText(source);  
        try{  
            List<ImageData> imageData = future.get();  
            for(ImageData data : imageData) {  
                rederImage(data);  
            }  
        } catch (InterruptedException e) {  
            //重新設置線程的中斷狀態  
            Thread.currentThread().interrupt();  
            //由於不需要結束,因此取消任務  
            future.cancel(true);  
        } catch (ExecutionException e) {  
            throw launderThrowable(e.getCause());  
        }  
    }  
}  

我們還可以通過Future的get方法來爲任務設置時間限制:
V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一樣,多了設置超時時間。參數timeout指定超時時間,uint指定時間的單位,在枚舉類TimeUnit中有相關的定義。如果計算超時,將拋出TimeoutException

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章