目錄
0、插播2020CSDN博客之星投票新聞
一、開篇
二、并發與并行
三、并發程式帶來關鍵問題
1、資料競爭
2、死鎖
3、活鎖
4、資源不足
5、優先權反轉
四、Java并發API(詳細)
1、基本并發類
2、同步機制
3、執行器
4、Fork/Join框架
5、并發資料結構
五、并發設計模式
1、信號模型
2、會合模式
3、互斥模式
4、讀寫鎖模式
5、執行緒池模式
6、執行緒區域存盤模式
六、最后總結
0、插播2020CSDN博客之星投票新聞
近日(1月11日-1月24日),2020CSDN博客之星評選正在火熱進行中,作為碼齡1年的小白有幸入選Top 200,首先很感謝CSDN官方把我選上,本來以為只是來湊熱鬧,看大佬們PK ^_^#,
綜合過去4天大佬們戰況,前十名大佬坐得很穩,不得不令人佩服點贊!真正的實力可以看出,文章數量不重要,更重要的是質量!一切用資料說話,如圖:
截至 2021-01-15 14:40:01

看了大佬的驚人資料,與我差距甚大,不禁感慨,小白只希望進Top 100,希望看到這條新聞的大佬、朋友們、粉絲們、和我一樣的小白們,能頂我一下,為我投全票,新年一起加油進步,萬事如意!^_^#
投票地址:https://bss.csdn.net/m/topic/blog_star2020/detail?username=charzous
或者掃碼投票:


重點:每一個投票都會被記錄,投了票的后面找Charzous幫忙也容易了(瘋狂暗示投票拉票)
即日起到24號,每天都可以投票哦,票數越多,貢獻排行榜就越靠前,我就記住你的名字啦!
一、開篇
在我之前寫的許多關于Java網路編程的博文中,已經初步使用了多執行緒的技術,是java并發的相關應用案例,而現在,需要學習一些關于并發程式設計的原理,弄懂來龍去脈,相對更加深入地理解并發設計原理,而且我發現,前面學習Java網路編程之后,有了實踐性的理解,再學習其相關原理,比較容易理解原理方面的知識,
這一篇記錄一下我學習的重要知識,整理出來感覺更容易看到,也是方便以后重溫學習查看!
二、并發與并行
很奇妙,并發和并行兩個概念在作業系統的課程上有學習過,當時只是在作業系統層面上理論的學習,未涉及實際應用場景和編程語言,現在重溫知識進一步學習,發現理解起來更實際了,
并發和并行概念有許多定義,整理一下好理解的幾個:
并發是指2個或多個活動在同一時間間隔內發生,在多道程式設計中,是指在同一時間段內有多個程式任務同時運行,也就是宏觀上同時執行,微觀上是串行的,
并行是指在微觀上多個任務同時執行,發生在同一個時間點上,顯然,要求多個程式任務并行運行,就需要多個處理器,在單處理器系統中,只有并發而無并行
在單個處理器上采用單核執行多個任務即為并發,作業系統的調度程式會很快從一個任務切換到另一個任務,因此看起來所有任務都是同時運行的,而同一時間在不同處理器或處理器核心上同時執行多個任務,就是并行,
最關鍵的還是并發原理以及設計,在并發中一個重要概念“同步”由此引出,
同步是一種協調兩個或多個任務以獲得預期結果的機制,包括:
- 控制同步:任務依賴關系,當一個任務的執行需要依賴于另一個任務的結束時,第二個任務不能在前者完成之前開始,
- 資料訪問同步:當兩個或多個任務訪問共享變數時,在任意時間里,只有一個任務可以訪問該變數,
與同步密切相關的一個概念是臨界段,它是一段代碼,用來保證在任意時間內只有一個任務能夠訪問共享資源,而互斥就是用來保證這個臨界段的機制,
三、并發程式帶來關鍵問題
并發程式的撰寫設計需要在同步/互斥機制上做許多作業,才能保證并發程式正確執行,所以,需要關注下面幾個關鍵問題,
1、資料競爭
簡單來說,就是多個任務對共享變數進行寫入操作,而沒有同步機制的臨界段作為約束,程式就存在資料競爭,
public class Account{
private float balance;
public void modify(float difference){
float value=this.balance;
this.balance=value+difference;
}
}
例如,上面的例子,如果存在兩個任務執行同一個Account物件進行modify操作,初始balance=1000,最終應該是3000,但是如果兩個任務同時執行了modify方法的第一條陳述句,又同時執行第二條陳述句,結果變為2000,因此,Account類不是執行緒安全的,沒有實作原子操作和同步機制,
2、死鎖
簡單來講,就是兩個或多個任務正在等待另一執行緒釋放的某個資源,而這個執行緒也正在等待前面的任務釋放的資源,這樣的并發程式就出現了死鎖,
完全滿足以下條件時候,就會導致死鎖,
- 互斥條件:死鎖中的資源是不可共享的,一個時間段內只有一個任務可以使用該資源,
- 請求和保持條件:任務已經保持了至少一個資源,但又提出新的請求,而該資源需要等待釋放,此時該任務阻塞等待,同時不會釋放自己獲得的資源,
- 非剝奪條件:資源只能被那些持有他們的任務釋放,
- 回圈等待條件:任務1正等待任務2占用的資源,任務2又正在等待任務3占用的資源,……,這樣出現回圈等待,
處理死鎖的方法有:預防、避免、檢測、解除,這四個基本方法都有具體實作的演算法,
3、活鎖
如果系統中有兩個任務,總是因為對方的行為而改變自己的狀態,就會出現活鎖,
舉個栗子,任務1、2都需要資源1、2,此時任務1擁有資源1并加鎖,任務2擁有資源2并加鎖,當他們無法訪問所需資源時候,就釋放自己的資源并開始新的回圈,這樣無限持續下去,兩個任務都不會結束自己的執行程序,
4、資源不足
活鎖就是一種資源不足的情況,當任務在系統中無法獲取所需資源繼續執行任務,
解決方法就是要確保公平原則,
5、優先權反轉
當一個低優先權任務持有高優先權任務所需資源時,就會發生優先權反轉,低優先權的任務會提前執行,
四、Java并發API(詳細)
java包含了豐富的并發API,在并發程式設計時候可以靈活使用,
1、基本并發類
- Thread類:描述了執行并發Java應用程式的所有執行緒,
- Runnable介面:Java中創建并發程式的另一種方式,
- ThreadLocal類:用于存放從屬于某個執行緒的變數,(沒有同步機制時使用)
- ThreadFactory介面:實作Factory設計模式的基類,用以創建定制執行緒,
2、同步機制
Java并發的同步機制支持定義訪問某個共享資源的臨界段;在某一共同點上同步不同的任務,
- sychronized關鍵字:可以在一個代碼塊或完整方法中定義一個臨界段,
- Lock介面:提供更豐富靈活的同步操作,其中ReentantLock用于實作一個條件關聯鎖;ReentantRead-WriteLock將讀寫操作分離;StampedLock包括了控制讀/寫訪問的模式,是Java8新增的特性,
以下幾個比較陌生:
- CountDownLatch類:允許多個任務等待多項操作的結束,
- CyclicBarrier類:允許多執行緒在某個共同點上進行同步,
- Phaser類:允許控制那些被分為多階段的任務的執行,所有任務在完成當前階段分任務前,不能進入下個階段,
3、執行器
- Executor介面和ExecutorService介面:包括共有的execute方法,
- ThreadPoolExecutor類:可以定義執行緒池執行器任務的最大數目,
- ScheduledThreadPoolExecutor類:一種特殊的執行器,在一段延遲之后執行任務或周期性執行任務,
- Callable介面:提供回傳值的Runnable介面的代替介面,
- Future介面:包含獲取Callable回傳值并控制其狀態的方法,
4、Fork/Join框架
該框架定義了一種特殊的執行器,尤其針對分治求解問題,提供了一種優化機制,開銷小,主要類和介面:
- ForkJoinPool:實作了用于運行任務的執行器,
- ForkJoinTask:可以在上述類中執行的任務,
- ForkJoinWorkerThread:準備在1類中執行任務的執行緒,
5、并發資料結構
Java中常用的資料結構如:ArrayList、Map、HashMap等都不能在并發程式中使用,因為沒有采取同步機制,不是執行緒安全的,如果自行采用同步機制,程式計算開銷增大,
因此,Java提供了并發程式中特殊的資料結構,屬于執行緒安全,主要有兩個類別:
- 阻塞型資料結構:包含了阻塞呼叫任務的方法,比如當獲取值時候該資料結果為空,
- 非阻塞型資料結構:操作可以立即進行,不會阻塞呼叫任務,
常用的并發資料結構(執行緒安全):
- ConcurrentHashMap:非阻塞哈希表(關鍵字Concurrent開頭的其他資料結構)
- ConcurrentLinkedDeque:非阻塞型串列
- LinkedBlockQueue:阻塞型佇列
- CopyOnWriteArrayList:讀讀共享、寫寫互斥、讀寫互斥,
- 實作了List介面
- 內部持有一個ReentrantLock lock = new ReentrantLock();
- 底層是用volatile transient宣告的陣列 array
- 讀寫分離,寫時復制出一個新的陣列,完成插入、修改或者移除操作后將新陣列賦值給array
5.PriorityBlockingQueue:阻塞型佇列,基于優先級對元素進行排序,
6.AtomicBoolean、AtomicInteger、AtomicLong和AtomicReference:基本Java資料型別的原子實作,(可使用原子變數代替同步)
五、并發設計模式
1、信號模型
實作該模式課采用信號量或者互斥,Java中的ReentrantLock或Semaphore,或者Object類的wait和notify方法,
public void task1(){
section1();
commonObject.notify();
}
public void task2(){
commonObject.wait();
section2();
}
section2方法總是在section1之后執行,
2、會合模式
信號模式的推廣,第一個任務將等待第二個任務某個活動的完成,而第二個任務也在等待第一個任務某個活動的完成,區別在于使用到兩個物件,
public void task1(){
section1_1();
commonObject1.notify();
commonObject2.wait();
section1_2();
}
public void task2(){
section2_1();
commonObject2.notify();
commonObject1.wait();
section2_2();
}
其中的陳述句順序不能修改,否則可能出現死鎖,
section2_2總是在section1_1后執行, section1_2總是在section2_1后執行.
3、互斥模式
互斥機制用以實作臨界段,確保操作相互排斥,
public void task1() {
preSection();
try {
lockObject.lock();//臨界段開始
section();
}catch (Exception e){
……
}finally {
lockObject.unlock();//臨界段結束
postSection();
}
}
4、讀寫鎖模式
該模式定義了一種特殊的鎖,包含兩個內部鎖:一個用于讀操作,一個用于寫操作,
鎖的特點:讀讀共享、寫寫互斥、讀寫互斥,
Java并發API的ReentrantReadWriteLock類實作了這種模式
5、執行緒池模式
該模式應用廣泛,減少了每次為每個任務創建執行緒的開銷,它是由一個執行緒集合和一個待執行任務佇列構成,ExceutorService介面可以實作該模式,
6、執行緒區域存盤模式
Java中的ThreadLocal類實作了執行緒區域變數,可以使用執行緒區域存盤,每個執行緒會訪問該變數不同實體,
六、最后總結
并發演算法設計遵循:
1、使用執行緒安全的Java并發API
2、在靜態類和共享場合使用區域執行緒變數
3、避免死鎖:對鎖排序
4、使用原子變數
這一篇我記錄了學習并發設計原理的關鍵知識,還有一些常用重要的Java并發編程API,在學習理論知識后,對這個部分有了更深層的理解,如果能夠加上實踐專案或者具體地案例分析,才能算真正掌握,因此,我也找了比較實際的案例進行實踐——檔案搜索,將在下一篇的博客進行詳細記錄,希望理論+實踐結合,知識的理解更進一步!
如果覺得不錯歡迎“一鍵三連”哦,點贊收藏關注,有問題直接評論,交流學習!
我的CSDN博客:https://blog.csdn.net/Charzous/article/details/112603639
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/249432.html
標籤:其他
