Java并发编程(多线程)中的相关概念
? ? 眾所周知,在Java的知識體系中,并發(fā)編程是非常重要的一環(huán),也是面試中必問的題,一個好的Java程序員是必須對并發(fā)編程這塊有所了解的。
并發(fā)必須知道的概念
在深入學習并發(fā)編程之前,我們需要了解幾個基本的概念。
同步和異步
同步和異步用請求返回調(diào)用的方式來理解相對簡單。
同步:可以理解為發(fā)出一個請求后,必須等待返回結果才能執(zhí)行后續(xù)的操作。
異步:請求發(fā)出后,不需要等待返回結果,可以繼續(xù)執(zhí)行后續(xù)操作,異步請求更像是在另一個 “空間” 中處理請求的結果,這個過程不會影響請求方的其他操作。
舉個生活中的例子,比如我們?nèi)嶓w店買衣服,挑選完款式后下單讓售貨員去倉庫拿貨,在售貨員拿貨的過程你需要在店里等待,直到售貨員把衣服交給你后才算購物成功,這就相當于同步的過程。
不過,如果是在網(wǎng)上購物的話,我們只需下單并完成支付,對我們來說整個購物過程就算完成了。網(wǎng)上的商家接到訂單會幫我們加緊安排送貨,這段時間我們可以去做其他的事,比如去外面打個籃球之類的。等送貨上門并簽收商品就完事了,這個過程就相當于異步。
并發(fā)和并行
并發(fā)和并行的功能很相似,兩者都可以表示多個任務一起執(zhí)行的情況,但本質(zhì)上兩者其實是有區(qū)別的。
嚴格意義上來說,并行的多任務是真實的同時執(zhí)行,而并發(fā)更多的情況是任務之間交替執(zhí)行,系統(tǒng)不停的在多個任務間切換執(zhí)行,也就是 “串行” 執(zhí)行。
最直接的例子的就是我們的計算機系統(tǒng),在單核CPU時代,系統(tǒng)表面上能同時進行多任務處理,比如聽歌的同時又瀏覽網(wǎng)頁,但真實環(huán)境中這些任務不可能是真實并行的,因為一個CPU一次只能執(zhí)行一條指令,這種情況就是并發(fā),系統(tǒng)看似能處理多任務是因為不停的切換任務,但因為時間非常短,所以在我們的感官來說就是同時進行的。而計算機系統(tǒng)真實的并行是隨著多核CPU的出現(xiàn)才有的。
臨界區(qū)
臨界區(qū)表示公共資源或是共享數(shù)據(jù),可以被多個線程使用。但是每次只能有一個線程使用它,一旦臨界區(qū)的資源被占用,其他線程就必須等到資源釋放后才能繼續(xù)使用該資源。在Java程序開發(fā)中,對于這樣的資源一般都需要做同步的操作,例如下面的這段代碼,用的就是synchronized關鍵字來對臨界區(qū)資源進行同步
public class SyncTest implements Runnable {//臨界區(qū)資源 public static SyncTest instance = new SyncTest();
阻塞和非阻塞
阻塞和非阻塞通常用來形容多線程間的相互影響。比如一個線程占用了臨界區(qū)的資源,那么其他需要這個資源的線程就必須等待。等待的過程會使線程掛起,也就是阻塞。如果臨界區(qū)的資源一直不釋放的話,那么其他阻塞的線程就都不能工作了。
非阻塞則相反,強調(diào)的是線程之間并不互相妨礙,所有的線程都會不斷嘗試向前執(zhí)行。
死鎖、饑餓和活鎖
這三種情況表示的是多線程間的活躍狀態(tài),對于線程來說,以上的情況都是 “非友好” 的狀態(tài)。
1、死鎖一般是指兩個或者兩個以上的線程互相持有對方所需的資源,并且永遠在等待對方釋放的一種阻塞狀態(tài)。例如有兩個線程A和B同時共享臨界區(qū)的資源C,當A占用C時,B處于阻塞狀態(tài),然而A的釋放需要用到B的資源,這樣一來,就變成了A一直在等待B,B也一直在等待A,互相之間永遠在等待對方釋放的狀態(tài)。
一般來說,死鎖的發(fā)生是由于程序的設計不合理導致,而且死鎖很難解決,最好的方式就是預防。
2、饑餓是指某一個或者多個線程因為種種原因無法獲得所需的資源,導致一直無法執(zhí)行。比如它的線程優(yōu)先級太低,而高優(yōu)先級的線程不斷搶占它所需的資源,導致低優(yōu)先級資源無法工作。
3、活鎖的情況是線程一種非常有趣的情況,在生活中我們可能會碰到這樣的情況,那就是出門的時候可能會遇到有人要進門,你打算讓他先進門,他又打算讓你先出門,結果,兩個人都互相退后了,然后你打算先出門時對方也向前一步,來來回回就一直卡在門口。當然,這種事情正常人很快就能解決,但如果是線程碰到就沒那么幸運了。
如果兩個線程占用著公共的資源,并且秉承著 “謙讓” 的原則,主動把資源讓給他人使用,你讓我也讓,這樣就造成資源在兩個線程間不斷跳動但線程之間都拿不到資源的情況,這樣的情況就是活鎖了。
線程安全
線程安全指的是多線程的安全。如果一段程序可以保證被多線程訪問后仍能保持正確性,那么程序就是線程安全的。一般來說,線程安全注重的是多線程開發(fā)中的共享數(shù)據(jù)的安全。就比如下面這段代碼:
public class ThreadSafety implements Runnable{//共享數(shù)據(jù) public static int i = 0; public void increase(){ for (int j= 0;j<10; j++){ i++; } }
兩個線程 t1 和 t2 同時開啟,執(zhí)行run方法,在我們的預想中,如果是線程安全的話,那么main的執(zhí)行結果應該是20,但是因為 i 是共享數(shù)據(jù),而程序沒有對 i 的操作做同步的處理,最終運行的結果并不是20,所以這種情況就不是線程安全的情況。
解決的辦法也比較簡單,可以利用synchronized關鍵字來修飾方法或代碼塊,這部分的知識也是并發(fā)編程中非常重要的一塊。
改進后的代碼如下:
public class ThreadSafety implements Runnable{//共享數(shù)據(jù) public static int i = 0; public void increase(){
synchronized(this){
for(int j= 0;j<10; j++){ i++; }
} }
?此時,兩個線程 t1 和 t2 同時開啟,執(zhí)行run方法,資源i就是獨立的了,兩個線程會切換執(zhí)行,當t1執(zhí)行的時候,會通過synchronized同步鎖將i鎖住,等到t1執(zhí)行完畢釋放鎖了之后,t2才會執(zhí)行對i進行操作。
轉(zhuǎn)載于:https://www.cnblogs.com/zhaosq/p/10178265.html
總結
以上是生活随笔為你收集整理的Java并发编程(多线程)中的相关概念的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1.1收集域名信息-完整介绍
- 下一篇: MISC-BUUCTF-9题-九连环-佛