并發(fā)編程的優(yōu)缺點

原創(chuàng)文章&經(jīng)驗總結(jié)&從校招到A廠一路陽光一路滄桑

詳情請戳www.codercc.com

image

一直以來并發(fā)編程對于剛?cè)胄械男“讈碚f總是覺得高深莫測勇劣,于是乎谬盐,就誕生了想寫點東西記錄下子巾,以提升理解和堆并發(fā)編程的認知模狭。為什么需要用的并發(fā)衔沼?凡事總有好壞兩面晰甚,之間的trade-off是什么降瞳,也就是說并發(fā)編程具有哪些缺點寺庄?以及在進行并發(fā)編程時應(yīng)該了解和掌握的概念是什么?這篇文章主要以這三個問題來談一談力崇。

1. 為什么要用到并發(fā)

一直以來斗塘,硬件的發(fā)展極其迅速,也有一個很著名的"摩爾定律"亮靴,可能會奇怪明明討論的是并發(fā)編程為什么會扯到了硬件的發(fā)展馍盟,這其中的關(guān)系應(yīng)該是多核CPU的發(fā)展為并發(fā)編程提供的硬件基礎(chǔ)。摩爾定律并不是一種自然法則或者是物理定律茧吊,它只是基于認為觀測數(shù)據(jù)后贞岭,對未來的一種預(yù)測。按照所預(yù)測的速度搓侄,我們的計算能力會按照指數(shù)級別的速度增長瞄桨,不久以后會擁有超強的計算能力,正是在暢想未來的時候讶踪,2004年芯侥,Intel宣布4GHz芯片的計劃推遲到2005年,然后在2004年秋季乳讥,Intel宣布徹底取消4GHz的計劃柱查,也就是說摩爾定律的有效性超過了半個世紀戛然而止。但是云石,聰明的硬件工程師并沒有停止研發(fā)的腳步唉工,他們?yōu)榱诉M一步提升計算速度,而不是再追求單獨的計算單元汹忠,而是將多個計算單元整合到了一起淋硝,也就是形成了多核CPU雹熬。短短十幾年的時間,家用型CPU,比如Intel i7就可以達到4核心甚至8核心谣膳。而專業(yè)服務(wù)器則通掣捅ǎ可以達到幾個獨立的CPU,每一個CPU甚至擁有多達8個以上的內(nèi)核参歹。因此,摩爾定律似乎在CPU核心擴展上繼續(xù)得到體驗隆判。因此犬庇,多核的CPU的背景下,催生了并發(fā)編程的趨勢侨嘀,通過并發(fā)編程的形式可以將多核CPU的計算能力發(fā)揮到極致臭挽,性能得到提升

頂級計算機科學(xué)家Donald Ervin Knuth如此評價這種情況:在我看來咬腕,這種現(xiàn)象(并發(fā))或多或少是由于硬件設(shè)計者無計可施了導(dǎo)致的欢峰,他們將摩爾定律的責(zé)任推給了軟件開發(fā)者。

另外涨共,在特殊的業(yè)務(wù)場景下先天的就適合于并發(fā)編程纽帖。比如在圖像處理領(lǐng)域,一張1024X768像素的圖片举反,包含達到78萬6千多個像素懊直。即時將所有的像素遍歷一邊都需要很長的時間,面對如此復(fù)雜的計算量就需要充分利用多核的計算的能力火鼻。又比如當我們在網(wǎng)上購物時室囊,為了提升響應(yīng)速度,需要拆分魁索,減庫存融撞,生成訂單等等這些操作,就可以進行拆分利用多線程的技術(shù)完成粗蔚。面對復(fù)雜業(yè)務(wù)模型尝偎,并行程序會比串行程序更適應(yīng)業(yè)務(wù)需求,而并發(fā)編程更能吻合這種業(yè)務(wù)拆分 鹏控。正是因為這些優(yōu)點冬念,使得多線程技術(shù)能夠得到重視,也是一名CS學(xué)習(xí)者應(yīng)該掌握的:

  • 充分利用多核CPU的計算能力牧挣;
  • 方便進行業(yè)務(wù)拆分急前,提升應(yīng)用性能

2. 并發(fā)編程有哪些缺點

多線程技術(shù)有這么多的好處,難道就沒有一點缺點么瀑构,就在任何場景下就一定適用么裆针?很顯然不是刨摩。

2.1 頻繁的上下文切換

時間片是CPU分配給各個線程的時間,因為時間非常短世吨,所以CPU不斷通過切換線程澡刹,讓我們覺得多個線程是同時執(zhí)行的,時間片一般是幾十毫秒耘婚。而每次切換時罢浇,需要保存當前的狀態(tài)起來,以便能夠進行恢復(fù)先前狀態(tài)沐祷,而這個切換時非常損耗性能嚷闭,過于頻繁反而無法發(fā)揮出多線程編程的優(yōu)勢。通常減少上下文切換可以采用無鎖并發(fā)編程赖临,CAS算法胞锰,使用最少的線程和使用協(xié)程。

  • 無鎖并發(fā)編程:可以參照concurrentHashMap鎖分段的思想兢榨,不同的線程處理不同段的數(shù)據(jù)嗅榕,這樣在多線程競爭的條件下,可以減少上下文切換的時間吵聪。

  • CAS算法凌那,利用Atomic下使用CAS算法來更新數(shù)據(jù),使用了樂觀鎖吟逝,可以有效的減少一部分不必要的鎖競爭帶來的上下文切換

  • 使用最少線程:避免創(chuàng)建不需要的線程案怯,比如任務(wù)很少,但是創(chuàng)建了很多的線程澎办,這樣會造成大量的線程都處于等待狀態(tài)

  • 協(xié)程:在單線程里實現(xiàn)多任務(wù)的調(diào)度嘲碱,并在單線程里維持多個任務(wù)間的切換

由于上下文切換也是個相對比較耗時的操作,所以在"java并發(fā)編程的藝術(shù)"一書中有過一個實驗局蚀,并發(fā)累加未必會比串行累加速度要快麦锯。 可以使用Lmbench3測量上下文切換的時長 vmstat測量上下文切換次數(shù)

2.2 線程安全

多線程編程中最難以把握的就是臨界區(qū)線程安全問題,稍微不注意就會出現(xiàn)死鎖的情況琅绅,一旦產(chǎn)生死鎖就會造成系統(tǒng)功能不可用扶欣。

public class DeadLockDemo {
    private static String resource_a = "A";
    private static String resource_b = "B";

    public static void main(String[] args) {
        deadLock();
    }

    public static void deadLock() {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource_a) {
                    System.out.println("get resource a");
                    try {
                        Thread.sleep(3000);
                        synchronized (resource_b) {
                            System.out.println("get resource b");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (resource_b) {
                    System.out.println("get resource b");
                    synchronized (resource_a) {
                        System.out.println("get resource a");
                    }
                }
            }
        });
        threadA.start();
        threadB.start();

    }
}

在上面的這個demo中,開啟了兩個線程threadA, threadB,其中threadA占用了resource_a, 并等待被threadB釋放的resource _b千扶。threadB占用了resource _b正在等待被threadA釋放的resource _a料祠。因此threadA,threadB出現(xiàn)線程安全的問題,形成死鎖澎羞。同樣可以通過jps,jstack證明這種推論:

"Thread-1":
  waiting to lock monitor 0x000000000b695360 (object 0x00000007d5ff53a8, a java.lang.String),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x000000000b697c10 (object 0x00000007d5ff53d8, a java.lang.String),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at learn.DeadLockDemo$2.run(DeadLockDemo.java:34)
        - waiting to lock <0x00000007d5ff53a8(a java.lang.String)
        - locked <0x00000007d5ff53d8(a java.lang.String)
        at java.lang.Thread.run(Thread.java:722)
"Thread-0":
        at learn.DeadLockDemo$1.run(DeadLockDemo.java:20)
        - waiting to lock <0x00000007d5ff53d8(a java.lang.String)
        - locked <0x00000007d5ff53a8(a java.lang.String)
        at java.lang.Thread.run(Thread.java:722)

Found 1 deadlock.

如上所述髓绽,完全可以看出當前死鎖的情況。

那么妆绞,通乘撑唬可以用如下方式避免死鎖的情況:

  1. 避免一個線程同時獲得多個鎖枫攀;
  2. 避免一個線程在鎖內(nèi)部占有多個資源,盡量保證每個鎖只占用一個資源株茶;
  3. 嘗試使用定時鎖来涨,使用lock.tryLock(timeOut),當超時等待時當前線程不會阻塞启盛;
  4. 對于數(shù)據(jù)庫鎖蹦掐,加鎖和解鎖必須在一個數(shù)據(jù)庫連接里,否則會出現(xiàn)解鎖失敗的情況

所以僵闯,如何正確的使用多線程編程技術(shù)有很大的學(xué)問卧抗,比如如何保證線程安全,如何正確理解由于JMM內(nèi)存模型在原子性棍厂,有序性颗味,可見性帶來的問題超陆,比如數(shù)據(jù)臟讀牺弹,DCL等這些問題(在后續(xù)篇幅會講述)。而在學(xué)習(xí)多線程編程技術(shù)的過程中也會讓你收獲頗豐时呀。

3. 應(yīng)該了解的概念

3.1 同步VS異步

同步和異步通常用來形容一次方法調(diào)用张漂。同步方法調(diào)用一開始,調(diào)用者必須等待被調(diào)用的方法結(jié)束后谨娜,調(diào)用者后面的代碼才能執(zhí)行航攒。而異步調(diào)用,指的是趴梢,調(diào)用者不用管被調(diào)用方法是否完成漠畜,都會繼續(xù)執(zhí)行后面的代碼,當被調(diào)用的方法完成后會通知調(diào)用者坞靶。比如憔狞,在超時購物,如果一件物品沒了彰阴,你得等倉庫人員跟你調(diào)貨瘾敢,直到倉庫人員跟你把貨物送過來,你才能繼續(xù)去收銀臺付款尿这,這就類似同步調(diào)用簇抵。而異步調(diào)用了,就像網(wǎng)購射众,你在網(wǎng)上付款下單后碟摆,什么事就不用管了,該干嘛就干嘛去了叨橱,當貨物到達后你收到通知去取就好焦履。

3.2 并發(fā)與并行

并發(fā)和并行是十分容易混淆的概念拓劝。并發(fā)指的是多個任務(wù)交替進行,而并行則是指真正意義上的“同時進行”嘉裤。實際上郑临,如果系統(tǒng)內(nèi)只有一個CPU光羞,而使用多線程時孝宗,那么真實系統(tǒng)環(huán)境下不能并行,只能通過切換時間片的方式交替進行西饵,而成為并發(fā)執(zhí)行任務(wù)典奉。真正的并行也只能出現(xiàn)在擁有多個CPU的系統(tǒng)中躺翻。

3.3 阻塞和非阻塞

阻塞和非阻塞通常用來形容多線程間的相互影響,比如一個線程占有了臨界區(qū)資源卫玖,那么其他線程需要這個資源就必須進行等待該資源的釋放公你,會導(dǎo)致等待的線程掛起,這種情況就是阻塞假瞬,而非阻塞就恰好相反陕靠,它強調(diào)沒有一個線程可以阻塞其他線程,所有的線程都會嘗試地往前運行脱茉。

3.4 臨界區(qū)

臨界區(qū)用來表示一種公共資源或者說是共享數(shù)據(jù)剪芥,可以被多個線程使用。但是每個線程使用時琴许,一旦臨界區(qū)資源被一個線程占有税肪,那么其他線程必須等待。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末榜田,一起剝皮案震驚了整個濱河市益兄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌箭券,老刑警劉巖净捅,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異邦鲫,居然都是意外死亡灸叼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門庆捺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來古今,“玉大人,你說我怎么就攤上這事滔以∽叫龋” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵你画,是天一觀的道長抵碟。 經(jīng)常有香客問我桃漾,道長,這世上最難降的妖魔是什么拟逮? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任撬统,我火速辦了婚禮,結(jié)果婚禮上敦迄,老公的妹妹穿的比我還像新娘恋追。我一直安慰自己,他們只是感情好罚屋,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布苦囱。 她就那樣靜靜地躺著,像睡著了一般脾猛。 火紅的嫁衣襯著肌膚如雪撕彤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天猛拴,我揣著相機與錄音羹铅,去河邊找鬼。 笑死漆弄,一個胖子當著我的面吹牛睦裳,可吹牛的內(nèi)容都是我干的造锅。 我是一名探鬼主播撼唾,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼哥蔚!你這毒婦竟也來了倒谷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤糙箍,失蹤者是張志新(化名)和其女友劉穎渤愁,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體深夯,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡抖格,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了咕晋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雹拄。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖掌呜,靈堂內(nèi)的尸體忽然破棺而出滓玖,到底是詐尸還是另有隱情,我是刑警寧澤质蕉,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布势篡,位于F島的核電站翩肌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏禁悠。R本人自食惡果不足惜念祭,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碍侦。 院中可真熱鬧棒卷,春花似錦、人聲如沸祝钢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拦英。三九已至蜒什,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疤估,已是汗流浹背灾常。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留铃拇,地道東北人钞瀑。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像慷荔,于是被迫代替她去往敵國和親雕什。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容