Java併發編程筆記(一)

《Java併發編程實戰》水平很高,然而並非本好書。組織混亂、長篇大論、難以消化,中文翻譯也較死板。這裏是一篇批評此書的帖子,非常貼切。俗話說:「看到有這麼多人罵你,我就放心了」。html

然而知識老是要學的。這裏就總結一下書中及網絡上的內容,做爲Java併發編程之旅的結束,再也不浪費時間了。java

兩個部分

這本書實際上能夠分爲兩個部分。一是多線程的控制,二是併發同步的管理。把它們揉在一塊兒,思路很難清晰。本文就先介紹第一部分,多線程的控制。編程

Thread和Runnable

在Java 5.0以前,多線程編程就是直接操做Thread。能夠從Thread類派生一個類,或者實現Runnable接口的run()方法,而後調用Thread.start()啓動線程。數組

線程的幾種狀態:網絡

clipboard.png

Java 5.0增長了java.util.concurrent包,纔有了線程池等強大的工具。多線程

Java線程池

參見Java線程池系列文章。本文略作總結。併發

阻塞隊列 BlockingQueue

阻塞隊列,顧名思義,它在基本隊列的基礎上,還有阻塞的功能。即,若是隊列已滿,則入隊操做阻塞等待,直到有空位;若是隊列已空,則出隊操做阻塞等待,直到隊列有元素。相應的方法分別爲put()take()異步

阻塞隊列有幾種實現:異步編程

  1. ArrayBlockingQueue:基於數組結構的有界阻塞隊列,按 FIFO(先進先出)原則對元素進行排序。
  2. LinkedBlockingQueue:基於鏈表結構的阻塞隊列,按FIFO排序元素,吞吐量一般要高於ArrayBlockingQueue。
  3. SynchronousQueue:一個不存儲元素的阻塞隊列。每一個插入操做必須等到另外一個線程調用移除操做,不然插入操做一直處於阻塞狀態,吞吐量一般要高於LinkedBlockingQueue。
  4. PriorityBlockingQueue:一個具備優先級的無限阻塞隊列。

本身實現線程池

就是一個簡單的生產者、消費者模型。線程池中的線程是消費者,循環地從阻塞隊列中提取任務,執行任務。工具

Java線程池

Java線程池的接口是ExecutorService,它有幾個實現。以ThreadPoolExecutor爲例,它的使用方式是:

BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(5);  
          
ExecutorService threadPoolExecutor =  
        new ThreadPoolExecutor(  
                corePoolSize,  //初始線程數
                maxPoolSize,   //最大線程數
                keepAliveTime, //空閒線程最大存活時間 
                TimeUnit.MILLISECONDS,  //時間單位
                queue          // 任務的阻塞隊列
        );

要使用這個線程池,可使用它提供的以下方法:

  • execute(Runnable) 沒有返回值 。
  • submit(Runnable) 返回Future對象,表明未完成的結果(因爲Runnable沒有返回值因此內容爲空)。
  • submit(Callable) 返回Future對象,表明未完成的結果。
  • invokeAny(Collection) 執行全部任務,返回第一個完成的結果。
  • invokeAll(Collection) 執行全部任務,返回Future對象列表。

最後,使用shutdown()shutdownNow()來關閉線程池,中止其中的線程。前者採用後文講到的interrupt方式溫和關閉,後者則調用Thread.stop()強行關閉。

Executors類

上面的線程池使用起來仍是太具體了,還須要本身建立線程池,還要本身傳阻塞隊列進去,很差用。因而Java提供了一個幫助類Executors,很是經常使用。

來看它的經常使用方法:

  • newFixedThreadPool(): 建立固定數量的線程池。
  • newCachedThreadPool(): 建立動態維護線程數的線程池。
  • newSingleThreadExecutor(): 建立單線程的線程池。

Callable接口和Future接口

Runnable接口的問題在於沒有返回值,過於簡單了。所以加入了Callable接口。相比於Runnable,一是有返回值,二是能夠拋出異常。
Future就是異步編程中對一個尚未完成的任務的抽象,至關於C#中的Task。一樣有cancel()isDone()等方法,調用get()則阻塞地獲取結果。
FutureTaskFuture的一個具體實現類,而且不光實現了Future,還實現了Runnable接口,使其用舊方式也可調用。具體可見 Runnable、Callable、Future、FutureTask的區別

任務的取消

這是一個高級話題。Java建議不要用stop()粗暴地殺死線程,而是採用interrupt()這種溫和的方式。當線程調用wait()sleep()等阻塞時,對這個線程調用interrupt()會使線程醒來,並受到InterruptedException,且線程的中斷標記被設置。如何處理這種狀況取決於線程本身。具體參見這篇文章

相關文章
相關標籤/搜索