摘要:并發編程實戰水平很高,然而并不是本好書。一是多線程的控制,二是并發同步的管理。最后,使用和來關閉線程池,停止其中的線程。當線程調用或等阻塞時,對這個線程調用會使線程醒來,并受到,且線程的中斷標記被設置。
《Java并發編程實戰》水平很高,然而并不是本好書。組織混亂、長篇大論、難以消化,中文翻譯也較死板。這里是一篇批評此書的帖子,很是貼切。俗話說:“看到有這么多人罵你,我就放心了”。
然而知識總是要學的。這里就總結一下書中及網絡上的內容,作為Java并發編程之旅的結束,不再浪費時間了。
兩個部分這本書實際上可以分為兩個部分。一是多線程的控制,二是并發同步的管理。把它們揉在一起,思路很難清晰。本文就先介紹第一部分,多線程的控制。
Thread和Runnable在Java 5.0之前,多線程編程就是直接操作Thread。可以從Thread類派生一個類,或者實現Runnable接口的run()方法,然后調用Thread.start()啟動線程。
線程的幾種狀態:
Java 5.0增加了java.util.concurrent包,才有了線程池等強大的工具。
Java線程池參見Java線程池系列文章。本文略做總結。
阻塞隊列 BlockingQueue阻塞隊列,顧名思義,它在基本隊列的基礎上,還有阻塞的功能。即,如果隊列已滿,則入隊操作阻塞等待,直到有空位;如果隊列已空,則出隊操作阻塞等待,直到隊列有元素。相應的方法分別為put()和take()。
阻塞隊列有幾種實現:
ArrayBlockingQueue:基于數組結構的有界阻塞隊列,按 FIFO(先進先出)原則對元素進行排序。
LinkedBlockingQueue:基于鏈表結構的阻塞隊列,按FIFO排序元素,吞吐量通常要高于ArrayBlockingQueue。
SynchronousQueue:一個不存儲元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處于阻塞狀態,吞吐量通常要高于LinkedBlockingQueue。
PriorityBlockingQueue:一個具有優先級的無限阻塞隊列。
自己實現線程池就是一個簡單的生產者、消費者模型。線程池中的線程是消費者,循環地從阻塞隊列中提取任務,執行任務。
Java線程池Java線程池的接口是ExecutorService,它有幾個實現。以ThreadPoolExecutor為例,它的使用方式是:
BlockingQueuequeue = new ArrayBlockingQueue (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()則阻塞地獲取結果。
FutureTask是Future的一個具體實現類,并且不光實現了Future,還實現了Runnable接口,使其用舊方式也可調用。具體可見 Runnable、Callable、Future、FutureTask的區別。
這是一個高級話題。Java建議不要用stop()粗暴地殺死線程,而是采用interrupt()這種溫和的方式。當線程調用wait()或sleep()等阻塞時,對這個線程調用interrupt()會使線程醒來,并受到InterruptedException,且線程的中斷標記被設置。如何處理這種情況取決于線程自己。具體參見這篇文章。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/68538.html
摘要:前言并發編程的目的是讓程序跑的更快,但并不是啟動更多的線程,這個程序就跑的更快。盡可能降低上下文切換的次數,有助于提高并發效率。死鎖并發編程中的另一挑戰是死鎖,會造成系統功能不可用。 前言 并發編程的目的是讓程序跑的更快,但并不是啟動更多的線程,這個程序就跑的更快。有以下幾種挑戰。 挑戰及方案 上下文切換 單核CPU上執行多線程任務,通過給每個線程分配CPU時間片的方式來實現這個機制。...
摘要:本文探討并發中的其它問題線程安全可見性活躍性等等。當閉鎖到達結束狀態時,門打開并允許所有線程通過。在從返回時被叫醒時,線程被放入鎖池,與其他線程競爭重新獲得鎖。 本文探討Java并發中的其它問題:線程安全、可見性、活躍性等等。 在行文之前,我想先推薦以下兩份資料,質量很高:極客學院-Java并發編程讀書筆記-《Java并發編程實戰》 線程安全 《Java并發編程實戰》中提到了太多的術語...
摘要:目前看的部分主要是這個關鍵字。語言提供了,保證了所有線程能看到共享變量最新的值。前綴的指令在多核處理器下會做兩件事情將當前處理器緩存行的數據寫回到系統內存。 這一章節的話,主要是講一下在并發操作中常見的volatile、synchronized以及原子操作的相關知識。 目前看的部分主要是volatile這個關鍵字。 volatile 根據Java語言規范第3版中對volatile的定義...
摘要:純分享直接上干貨操作系統并發支持進程管理內存管理文件系統系統進程間通信網絡通信阻塞隊列數組有界隊列鏈表無界隊列優先級有限無界隊列延時無界隊列同步隊列隊列內存模型線程通信機制內存共享消息傳遞內存模型順序一致性指令重排序原則內存語義線程 純分享 , 直接上干貨! 操作系統并發支持 進程管理內存管...
摘要:前言今天的筆記來了解一下原子操作以及中如何實現原子操作。概念原子本意是不能被進一步分割的最小粒子,而原子操作意為不可被中斷的一個或一系列操作。處理器實現原子操作處理器會保證基本內存操作的原子性。 showImg(https://segmentfault.com/img/bVVIRA?w=1242&h=536); 前言 今天的筆記來了解一下原子操作以及Java中如何實現原子操作。 概念 ...
閱讀 853·2021-11-18 10:07
閱讀 2365·2021-10-14 09:42
閱讀 5367·2021-09-22 15:45
閱讀 601·2021-09-03 10:29
閱讀 3478·2021-08-31 14:28
閱讀 1886·2019-08-30 15:56
閱讀 3049·2019-08-30 15:54
閱讀 1003·2019-08-29 11:32