溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

[Java并發(fā)編程實(shí)戰(zhàn)] 簡(jiǎn)介

發(fā)布時(shí)間:2020-07-25 01:29:48 來(lái)源:網(wǎng)絡(luò) 閱讀:343 作者:seaicelin 欄目:移動(dòng)開(kāi)發(fā)

并發(fā)簡(jiǎn)史

在早期不包含操作系統(tǒng)的計(jì)算機(jī)中,程序都是單一的串行程序,從頭至尾只能執(zhí)行一個(gè)程序,并且這個(gè)程序訪問(wèn)這個(gè)計(jì)算機(jī)的所有資源。然而,隨著技術(shù)的發(fā)展,操作系統(tǒng)出現(xiàn)了。它使得計(jì)算機(jī)程序有了進(jìn)程,線程的概念,每次可以運(yùn)行多個(gè)程序,并且不同的程序都在單獨(dú)的進(jìn)程中運(yùn)行。操作系統(tǒng)為各個(gè)獨(dú)立執(zhí)行的進(jìn)程分配各種資源,包括內(nèi)存,文件句柄,安全證書(shū)等。不同進(jìn)程之間通過(guò)系統(tǒng)本身的通信機(jī)制來(lái)交換數(shù)據(jù),如:套接字,信號(hào)處理器,共享內(nèi)存,信號(hào)量以及文件等。
操作系統(tǒng)支持多個(gè)程序同時(shí)執(zhí)行,原因主要有:

  1. 資源利用率。如某個(gè)程序在等待一個(gè)耗時(shí)操作完成,那么在等待的同時(shí)可以運(yùn)行另外一個(gè)程序,這樣可以提高資源利用率。

  2. 公平性。如通過(guò)時(shí)間片的方式讓程序輪流占用計(jì)算機(jī)資源,而不是由一個(gè)程序從頭至尾運(yùn)行完,再進(jìn)行下一個(gè)。

  3. 便利性。編寫(xiě)多個(gè)程序來(lái)計(jì)算多個(gè)任務(wù),必要時(shí)進(jìn)行通信。比只編寫(xiě)一個(gè)程序來(lái)計(jì)算所有任務(wù)更加容易實(shí)現(xiàn)。

串行編程模型優(yōu)勢(shì)在于直觀性和簡(jiǎn)單性,每次只做一件事直至完成,然后再做另外一件。然而很多情況下,這個(gè)串行模型并不理想。打個(gè)比方,我們想燒水泡茶然后看書(shū),以串行的工作方式,我們必須等到水燒開(kāi)了把茶泡好,才能去看書(shū)。而現(xiàn)實(shí)生活中,完全可以燒水的過(guò)程先去看書(shū),然后等待水燒開(kāi)在去泡茶。這也引出了計(jì)算機(jī)應(yīng)用程序用,同步和異步的概念。正是這些原因,促使進(jìn)程,線程的出現(xiàn)。

線程,也被稱為輕量級(jí)進(jìn)程。現(xiàn)在大多數(shù)操作系統(tǒng)中,都是以線程為基本的調(diào)度單位,而不是進(jìn)程。一個(gè)進(jìn)程可以創(chuàng)建多個(gè)線程,并且這些線程會(huì)共享進(jìn)程范圍內(nèi)的資源。所以,多個(gè)線程如果沒(méi)有明確的協(xié)同機(jī)制,那么他們是獨(dú)立運(yùn)行的。同樣,這些線程都可以訪問(wèn)進(jìn)程的變量,如果沒(méi)有明確的同步機(jī)制來(lái)協(xié)同對(duì)共享數(shù)據(jù)的訪問(wèn),那么當(dāng)一個(gè)線程正在使用某個(gè)變量時(shí),另外一個(gè)線程可能同時(shí)訪問(wèn)這個(gè)變量,造成不可預(yù)測(cè)的結(jié)果。但是,每個(gè)線程都有各自的計(jì)數(shù)器,棧以及局部變量等。

線程的優(yōu)勢(shì)

如果使用得當(dāng),可以降低開(kāi)發(fā),維護(hù)成本,提升性能。線程還可以降低代碼復(fù)雜度,使得代碼更容易編寫(xiě),閱讀和維護(hù)。在GUI 程序中,可以提高界面的響應(yīng)速度;在服務(wù)端程序中,可以提升資源利用率和吞吐率。

  • 發(fā)揮多核處理器的強(qiáng)大能力。

  • 建模的簡(jiǎn)單性。將復(fù)雜且異步的工作流分解到各個(gè)線程運(yùn)行,在特定的同步位置進(jìn)行交互。

  • 異步事件的簡(jiǎn)化處理。某個(gè)線程的阻塞不影響其他線程的處理。

  • 響應(yīng)更靈敏的用戶界面。使用特定線程來(lái)處理耗時(shí)操作,而不是放在UI主線程中處理。比如 Android App 耗時(shí)事件不能在 UI 線程處理,會(huì)影響 UI 響應(yīng)的流暢度。

線程的風(fēng)險(xiǎn)

Java 對(duì)線程的使用是一把雙刃劍。線程的優(yōu)勢(shì)我們都已經(jīng)知道,前提是我們能夠正確的編寫(xiě)出安全的并發(fā)代碼。然而,由于開(kāi)發(fā)人員的技術(shù)不足,并發(fā)潛在風(fēng)險(xiǎn)的不易察覺(jué),都有可能讓我們的程序達(dá)不到預(yù)期的效果。所以,我們有必要了解一下并發(fā)風(fēng)險(xiǎn)這一方面的內(nèi)容。

安全性問(wèn)題

多個(gè)線程的執(zhí)行順序,在沒(méi)有同步的情況下是不可預(yù)測(cè)的,甚至產(chǎn)生奇怪的結(jié)果。如下面這個(gè)序列生成類,多個(gè)線程同時(shí)獲取到的值可能是相同的。

1    public class UnsafeSequene{
2        private int value;
3        //返回一個(gè)唯一的數(shù)值
4        public int getNext(){
5            return value++;
6        }
7    }

遞增操作 value++,實(shí)際上他包含三個(gè)獨(dú)立的操作:

  1. 讀取 value 的值

  2. 將 value 加 1

  3. 將計(jì)算結(jié)果寫(xiě)入 value
    由于多個(gè)線程之間的操作交替執(zhí)行,所以可能發(fā)生兩個(gè)線程讀到相同的值。如下圖所示的 A 線程和 B 線程: 
    [Java并發(fā)編程實(shí)戰(zhàn)] 簡(jiǎn)介這里寫(xiě)圖片描述
    上圖說(shuō)明的是一種常見(jiàn)的并發(fā)安全問(wèn)題,稱為競(jìng)態(tài)條件(Race Condition)。由于多個(gè)線程共享相同的內(nèi)存地址空間,并且是并發(fā)運(yùn)行,因此可能會(huì)訪問(wèn)或修改其他線程正在使用的變量。這種方式比其他線程間通信機(jī)制更容易實(shí)現(xiàn)數(shù)據(jù)共享,但他同樣也帶來(lái)了巨大的風(fēng)險(xiǎn):線程由于無(wú)法預(yù)料數(shù)據(jù)的變化而發(fā)生錯(cuò)誤。

幸運(yùn)的是,Java 提供了各種同步機(jī)制來(lái)協(xié)同這種訪問(wèn)。上面的示例代碼,把它改成一個(gè)同步方法,就可以防止這種錯(cuò)誤的發(fā)生。

1public class UnsafeSequene{
2    private int value;
3    //返回一個(gè)唯一的數(shù)值
4    public synchronized int getNext(){
5        return value++;
6    }
7}

活躍性問(wèn)題

安全性的含義是,永遠(yuǎn)不發(fā)生糟糕的事情?;钴S性是,某件正確的事情最終會(huì)發(fā)生。當(dāng)某個(gè)操作無(wú)法繼續(xù)執(zhí)行下去時(shí),就會(huì)發(fā)生活躍性問(wèn)題,比如程序代碼進(jìn)入死循環(huán)。所線程導(dǎo)致的死鎖,也是活躍性問(wèn)題,比如線程 A 在等待線程 B 釋放其持有的資源,而線程 B 永遠(yuǎn)都不釋放改資源,那么,線程 A 就會(huì)永遠(yuǎn)的等待下去。

性能問(wèn)題

活躍性意味著某件正確的事情最終會(huì)發(fā)生,但卻不夠好。這就是性能問(wèn)題,因?yàn)槲覀兺ǔOM_的事盡快發(fā)生。性能問(wèn)題包括:服務(wù)時(shí)間過(guò)長(zhǎng),響應(yīng)不靈敏,吞吐率過(guò)低,資源消耗過(guò)高等。

良好的并發(fā)程序,線程能提高性能,但無(wú)論如何,總會(huì)帶來(lái)某種程度的運(yùn)行時(shí)開(kāi)銷。
1.線程調(diào)度臨時(shí)掛起活躍線程并轉(zhuǎn)而運(yùn)行另一個(gè)線程時(shí),就會(huì)頻繁的出現(xiàn)上下文切換,帶來(lái)極大的開(kāi)銷:保存和恢復(fù)執(zhí)行上下文,CPU 時(shí)間更多的花在線程調(diào)度而不是線程運(yùn)行上。
2.使用同步機(jī)制,往往會(huì)抑制某些編譯器優(yōu)化。

線程無(wú)處不在

即使在程序中沒(méi)有顯示的創(chuàng)建線程,但在框架中仍可能會(huì)創(chuàng)建線程,因此在這些線程中調(diào)用的代碼同樣必須是線程安全的??蚣芡ㄟ^(guò)在框架線程中調(diào)用應(yīng)用程序代碼將并發(fā)性引入到程序中。在代碼中將不可避免地訪問(wèn)應(yīng)用程序狀態(tài),因此所有訪問(wèn)這些狀態(tài)的代碼路徑都必須是線程安全的。

下面給出的模塊都將在應(yīng)用程序之外的線程中調(diào)用應(yīng)用程序的代碼。

  1. Timer

  2. Servlet 和 JavaServer Page

  3. 遠(yuǎn)程調(diào)用方法

  4. Swing 和 AWT

本文原創(chuàng)首發(fā)于微信公眾號(hào) [ 林里少年 ],歡迎關(guān)注第一時(shí)間獲取更新。

[Java并發(fā)編程實(shí)戰(zhàn)] 簡(jiǎn)介這里寫(xiě)圖片描述


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI