總結了線程安全性的二十四個精華問題

?

1、對象的狀態:對象的狀態是指存儲在狀態變量中的數據,對象的狀態可能包括其他依賴對象的域。在對象的狀態中包含了任何可能影響其外部可見行為的數據。

?

2、一個對象是否是線程安全的,取決于它是否被多個線程訪問。這指的是在程序中訪問對象的方式,而不是對象要實現的功能。當多個線程訪問某個狀態變量并且其中有一個線程執行寫入操作時,必須采用同步機制來協同這些線程對變量的訪問。同步機制包括synchronized、volatile變量、顯式鎖、原子變量。

?

3、有三種方式可以修復線程安全問題:

1)不在線程之間共享該狀態變量

2)將狀態變量修改為不可變的變量

3)在訪問狀態變量時使用同步

?

4、線程安全性的定義:當多個線程訪問某個類時,不管運行時環境采用何種調度方式或者這些線程將如何交替執行,并且在主調代碼中不需要任何額外的同步,這個類都能表現出正確的行為,那么就稱這個類是線程安全的。

?

5、無狀態變量一定是線程安全的,比如局部變量。

?

6、讀取-修改-寫入操作序列,如果是后續操作是依賴于之前讀取的值,那么這個序列必須是串行執行的。在并發編程中,由于不恰當的執行時序而出現不正確的結果是一種非常重要的情況,它稱為競態條件(Race Condition)。最常見的競態條件類型就是先檢查后執行的操作,通過一個可能失效的觀測結果來決定下一步的操作。


7、復合操作:要避免競態條件問題,就必須在某個線程修改該變量時,通過某種方式防止其他線程使用這個變量,從而確保其他線程只能在修改操作完成之前或之后讀取和修改狀態,而不是在修改狀態的過程中。假定有兩個操作A和B,如果從執行A的線程看,當另一個線程執行B時,要么將B全部執行完,要么完全不執行B,那么A和B對彼此來說就是原子的。原子操作是指,對于訪問同一個狀態的所有操作來說,這個操作是一個以原子方式執行的操作。

為了確保線程安全性,讀取-修改-寫入序列必須是原子的,將其稱為復合操作。復合操作包含了一組必須以原子方式執行的接口以確保線程安全性。

?

8、在無狀態的類中添加一個狀態時,如果這個狀態完全由線程安全的對象來管理,那么這個類仍然是線程安全的。(比如原子變量)

?

9、如果多個狀態是相關的,需要同時被修改,那么對多個狀態的操作必須是串行的,需要進行同步。要保持狀態的一致性,就需要在單個原子操作中更新所有相關的狀態變量。

?

10、內置鎖:synchronized(object){同步塊}

Java的內置鎖相當于一種互斥體,這意味著最多只有一個線程能持有這種鎖,當線程A嘗試獲取一個由線程B持有的鎖時,線程A必須等待或阻塞,直到線程B釋放這個鎖。如果B永遠不釋放鎖,那么A也將永遠地等待下去。

?

11、重入:當某個線程請求一個由其他線程持有的鎖時,發出請求的線程就會阻塞。然而,由于內置鎖是可重入的,因此如果某個線程試圖獲得一個已經由它自己持有的鎖,那么這個請求就會成功。重入意味著獲取鎖的操作的粒度是線程,而不是調用。重入的一種實現方法是,為每個鎖關聯一個獲取計數值和一個所有者線程。當計數值為0時,這個鎖就被認為是沒有被任何線程持有。當線程請求一個未被持有的鎖時,JVM將記下鎖的持有者,并且將獲取計數值置1。如果一個線程再次獲取這個鎖,計數值將遞增,而當線程退出同步代碼塊時,計數值會相應遞減。當計數值為0時,這個鎖將被釋放。

?

12、對于可能被多個線程同時訪問的可變狀態變量,在訪問它時都需要持有同一個鎖,在這種情況下,我們稱狀態變量是由這個鎖保護的。

每個共享的和可變的變量都應該只由一個鎖來保護,從而使維護人員知道是哪一個鎖。

一種常見的加鎖約定是,將所有的可變狀態都封裝在對象內部,并提供對象的內置鎖(this)對所有訪問可變狀態的代碼路徑進行同步。在這種情況下,對象狀態中的所有變量都由對象的內置鎖保護起來。

?

13、不良并發:要保證同步代碼塊不能過小,并且不要將本應是原子的操作拆分到多個同步代碼塊中。應該盡量將不影響共享狀態且執行時間較長的操作從同步代碼塊中分離出去,從而在這些操作的執行過程中,其他線程可以訪問共享狀態。

?

14、可見性:為了確保多個線程之間對內存寫入操作的可見性,必須使用同步機制。

?

15、加鎖與可見性:當線程B執行由鎖保護的同步代碼塊時,可以看到線程A之前在同一個同步代碼塊中的所有操作結果。如果沒有同步,那么就無法實現上述保證。加鎖的含義不僅僅局限于互斥行為,還包括內存可見性。為了確保所有線程都能看到共享變量的最新值,所有執行讀操作或寫操作的線程都必須在同一個鎖上同步。

?

16、volatile變量:當把變量聲明為volatile類型后,編譯器與運行時都會注意到這個變量是共享的,因此不會將該變量上的操作與其他內存操作一起重排序。volatile變量不會被緩存在寄存器或其他對處理器不可見的地方,因此在讀取volatile類型的變量時總會返回最新寫入的值。volatile的語義不足以確保遞增操作的原子性,除非你能確保只有一個線程對變量執行寫操作。原子變量提供了“讀-改-寫”的原子操作,并且常常用做一種更好的volatile變量。

?

17、加鎖機制既可以確保可見性,又可以確保原子性,而volatile變量只能確保可見性。

?

18、當且僅當滿足以下的所有條件時,才應該使用volatile變量:

1)對變量的寫入操作不依賴變量的當前值(不存在讀取-判斷-寫入序列),或者你能確保只有單個線程更新變量的值

2)該變量不會與其他狀態變量一起納入不可變條件中

3)在訪問變量時不需要加鎖

?

19、棧封閉:在棧封閉中,只能通過局部變量才能訪問對象。維護線程封閉性的一種更規范的方法是使用ThreadLocal,這個類能使線程的某個值與保存值的對象關聯起來,ThreadLocal通過了get和set等訪問接口或方法,這些方法為每個使用該變量的線程都存有一份獨立的副本,因此get總是返回由當前執行線程在調用set時設置的最新值。

?

20、在并發程序中使用和共享對象時,可以使用一些使用的策略,包括:

1)線程封閉:線程封閉的對象只能由一個線程擁有,對象被封閉在該線程中,并且只能由這個線程修改。

2)只讀共享:在沒有額外同步的情況下,共享的只讀對象可以由多個線程并發訪問,但任何線程都不能修改它。共享的只讀對象包括不可變對象和事實不可變對象(從技術上來說是可變的,但其狀態在發布之后不會再改變)。

3)線程安全共享。線程安全的對象在其內部實現同步,因此多個線程可以通過對象的公有接口來進行訪問而不需要進一步的同步。

4)保護對象。被保護的對象只能通過持有對象的鎖來訪問。保護對象包括封裝在其他線程安全對象中的對象,以及已發布并且由某個特定鎖保護的對象。

?

21、饑餓:當線程由于無法訪問它所需要的資源而不能繼續執行時,就發生了饑餓(某線程永遠等待)。引發饑餓的最常見資源就是CPU時鐘周期。比如線程的優先級問題。在Thread API中定義的線程優先級只是作為線程調度的參考。在Thread API中定義了10個優先級,JVM根據需要將它們映射到操作系統的調度優先級。這種映射是與特定平臺相關的,因此在某個操作系統中兩個不同的Java優先級可能被映射到同一優先級,而在另一個操作系統中則可能被映射到另一個不同的優先級。

當提高某個線程的優先級時,可能不會起到任何作用,或者也可能使得某個線程的調度優先級高于其他線程,從而導致饑餓。

通常,我們盡量不要改變線程的優先級,只要改變了線程的優先級,程序的行為就將與平臺相關,并且會導致發生饑餓問題的風險。

?

事務T1封鎖了數據R,事務T2又請求封鎖R,于是T2等待。T3也請求封鎖R,當T1釋放了R上的封鎖后,系統首先批準了T3的請求,T2仍然等待。然后T4又請求封鎖R,當T3釋放了R上的封鎖之后,系統又批準了T的請求......T2可能永遠等待

?

22、活鎖

活鎖是另一種形式的活躍性問題,該問題盡管不會阻塞線程,但也不能繼續執行,因為線程將不斷重復執行相同的操作,而且總會失敗。活鎖通常發生在處理事務消息的應用程序中。如果不能成功處理某個消息,那么消息處理機制將回滾整個事務,并將它重新放到隊列的開頭。雖然處理消息的線程并沒有阻塞,但也無法繼續執行下去。這種形式的活鎖通常是由過度的錯誤恢復代碼造成的,因為它錯誤地將不可修復的錯誤作為可修復的錯誤。

?

當多個相互協作的線程都對彼此進行響從而修改各自的狀態,并使得任何一個線程都無法繼續執行時,就發生了活鎖。要解決這種活鎖問題,需要在重試機制中引入隨機性。在并發應用程序中,通過等待隨機長度的時間和回退可以有效地避免活鎖的發生。

?

23、當在鎖上發生競爭時,競爭失敗的線程肯定會阻塞。JVM在實現阻塞行為時,可以采用自旋等待(Spin-Waiting,指通過循環不斷地嘗試獲取鎖,直到成功),或者通過操作系統掛起被阻塞的線程。這兩種方式的效率高低,取決于上下文切換的開銷以及在成功獲取鎖之前需要等待的時間。如果等待時間較短,則適合采用自旋等待的方式,而如果等待時間較長,則適合采用線程掛起方式。

?

24、有兩個因素將影響在鎖上發生競爭的可能性:鎖的請求頻率,以及每次持有該鎖的時間。如果二者的乘積很小,那么大多數獲取鎖的操作都不會發生競爭,會因此在該鎖上的競爭不會對可伸縮性造成嚴重影響。然而,如果在鎖上的請求量很高,那么需要獲取該鎖的線程將被阻塞并等待。在極端情況下,即使仍有大量工作等待完成,處理器也會被閑置。

有3種方式可以降低鎖的競爭程度:

1)減少鎖的持有時間:

①縮小鎖的范圍,將與鎖無關的代碼移出同步代碼塊,尤其是開銷較大的操作以及可能被阻塞的操作(IO操作)。

當把一個同步代碼塊分解為多個同步代碼塊時,反而會對性能提升產生負面影響。在分解同步代碼塊時,理想的平衡點將與平臺相關,但在實際情況中,僅可以將一些大量的計算或阻塞操作從同步代碼塊移出時,才應該考慮同步代碼塊的大小。

②減小鎖的粒度:鎖分解和鎖分段

鎖分解是采用多個相互獨立的鎖來保護獨立的狀態變量,從而改變這些變量在之前由單個鎖來保護的情況。這些技術能減小鎖操作的粒度,并能實現更高的可伸縮性,然而,使用的鎖越多,那么發生死鎖的風險也就越高。

鎖分段:比如JDK1.7及之前的ConcurrentHashMap采用的方式就是分段鎖的方式。

2)降低鎖的請求頻率

3)使用帶有協調機制的獨占鎖,這些機制允許更高的并發性

比如讀寫鎖,并發容器等

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444762.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444762.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444762.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何在Appscale下發布自己的應用(二)

本文開始講如何發布自己的app應用到appscle上 建好appscle網站后,可以在命令行通過 appscle deploy apppathname 來發布自己應用。 除了用命令行提交應用之外,還可以通過appscale的網站直接提交,選擇 upload application->選擇上傳文件-&g…

Python模塊(7)-SciPy 簡易使用教程

SciPy 簡易使用教程1. 符號計算2. 函數向量化3. 波形處理scipy.signal3.1 濾波器3.2 波峰定位基于numpy的一個高級模塊,為數學,物理,工程等方面的科學計算提供無可替代的支持。 做重要的思想是:符號計算和函數向量化 1. 符號計算…

Xcode的Architectures和Valid Architectures的區別

目錄[-] Xcode的Architectures和Valid Architectures的區別 Architectures Valid Architectures 原因解釋如下: 參考1: 所有IOS設備詳情列表 List of iOS devices - Wikipedia, the free encyclopedia 參考2: iOS 7: 如何為iPhone 5S編譯64位…

Python模塊(8)-sklearn 簡易使用教程

sklearn 簡易使用教程1.scikit-learn的數據集2.scikit-learn 的訓練和預測scikit-learn 是在Numpy,SciPy,Matplotlib三個模塊上編寫的,數據挖掘和數據分析的一個簡單有效的工具。scikit-learn包括6大功能:分類,回歸,聚類&#xff…

如何發布GAE的應用(一)

安裝googleSDK的環境: 1 下載安裝包從官網下載 https://cloud.google.com/sdk/downloads -> https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-170.0.0-windows-x86_64-bundled-python.zip 2 如果本地安裝了python,直…

leetcode887 雞蛋掉落

你將獲得 K 個雞蛋&#xff0c;并可以使用一棟從 1 到 N 共有 N 層樓的建筑。 每個蛋的功能都是一樣的&#xff0c;如果一個蛋碎了&#xff0c;你就不能再把它掉下去。 你知道存在樓層 F &#xff0c;滿足 0 < F < N 任何從高于 F 的樓層落下的雞蛋都會碎&#xff0c;…

Docker 的日志相關整理

1 Docker daemon日志的位置 Docker daemon日志的位置&#xff0c;根據系統不同各不相同。 Ubuntu - /var/log/upstart/docker.logBoot2Docker - /var/log/docker.logDebian GNU/Linux - /var/log/daemon.logCentOS - /var/log/daemon.log | grep dockerFedora - journalctl -u…

PaperNotes(15)-圖神經網絡、PyG極簡版入門筆記

圖神經網絡概況1.GNN,GCN,GE的區別2.圖卷積的通式--矩陣該如何作用2.1實現12.2實現22.3實現33.PyTorch geometric3.1 PyG內置數據集3.1.1ENZYMES dataset3.1.2Cora3.2 PyG自定義數據集3.2.1Data構建簡單的圖結構3.2.2 Dataset3.2.3 InMemoryDataset一文讀懂圖卷積GCN(https://z…

leetcode76 最小覆蓋子串

給你一個字符串 S、一個字符串 T&#xff0c;請在字符串 S 里面找出&#xff1a;包含 T 所有字母的最小子串。 示例&#xff1a; 輸入: S "ADOBECODEBANC", T "ABC" 輸出: "BANC" 說明&#xff1a; 如果 S 中不存這樣的子串&#xff0c;則返…

Unity的匹配系統

這個匹配系統是指一個玩家&#xff0c;可以創建一個自己隨意命名的房間&#xff0c;然后其他玩家可以通過聯網去搜索房間&#xff0c;然后加入房間一起游戲 我先講講怎么使用這個匹配系統&#xff1a; 在運行游戲后&#xff0c;因為添加了Network Manager HUD組件&#xff0c;所…

PaperNotes(16)-圖神經網絡GNN簡史、不動點建模-筆記

圖神經網絡簡史、簡介1.圖神經網絡簡史2.圖神經網絡--學習過程3.圖神經網絡--理論基礎4.圖神經網絡的局限5.GNN,RNN,GGNN6.小結閱讀筆記&#xff1a;從圖(Graph)到圖卷積(Graph Convolution)&#xff1a;漫談圖神經網絡模型 (一)(https://www.cnblogs.com/SivilTaram/p/graph_n…

Matchmaker

Unity的多玩家網絡功能包含了玩家在因特網上互相玩而不需要公共IP地址的服務。用戶可以創建游戲,獲取活動游戲列表;加入并退出游戲。當在internet上玩時,網絡流量將通過云中的Unity,而不是直接在客戶端之間進行。這就避免了防火墻和NATs的問題,幾乎可以在任何地方玩游戲。 …

PaperNotes(17)-圖卷積神經網絡GCN-筆記

圖卷積神經網絡GCN-筆記1.卷積是什么2.圖卷積的源起3.空域卷積3.1消息傳遞網絡MPNN3.2 圖采樣與聚合GraphSage4.頻域卷積5.圖結構的序列化-Patch-SAN從圖(Graph)到圖卷積(Graph Convolution)&#xff1a;漫談圖神經網絡模型 (二)(https://www.cnblogs.com/SivilTaram/p/graph_n…

Servlet 工程 web.xml 中的 servlet 和 servlet-mapping 標簽

摘錄某個工程的 web.xml 文件片段&#xff1a;訪問順序為1—>2—>3—>4&#xff0c;其中2和3的值必須相同。 url-pattern 標簽中的值是要在瀏覽器地址欄中輸入的 url&#xff0c;可以自己命名&#xff0c;這個 url 訪問名為 servlet-name 中值的 servlet&#xff0c;兩…

leetcode236 二叉樹的最近公共祖先

給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。 百度百科中最近公共祖先的定義為&#xff1a;“對于有根樹 T 的兩個結點 p、q&#xff0c;最近公共祖先表示為一個結點 x&#xff0c;滿足 x 是 p、q 的祖先且 x 的深度盡可能大&#xff08;一個節點也可以是它自己的…

Unity的 UNet組件介紹

UNet常見概念簡介 Spawn:簡單來說,把服務器上的GameObject,根據上面的NetworkIdentity組件找到對應監視連接,在監視連接里生成相應的GameObject.Command:客戶端調用,服務器執行,這樣客戶端調用的參數必需要UNet可以序列化,這樣服務器在執行時才能把參數反序列化。需要注意…

MachineLearning(10)-聚類

聚類1.K-mean2.系統聚類3.DBSCAN聚類算法聚類&#xff1a;無監督學習&#xff0c;將相似的樣本聚為一類。核心如何定義相似。分類&#xff1a;有監督學習&#xff0c;依據分類準則&#xff0c;將樣本劃分為不同的類。核心分類器的設計&#xff08;KNN&#xff09;聚類&#xff…

幀同步和狀態同步(一)

幀同步 什么是幀同步&#xff1a;幀同步常被RTS(即時戰略)游戲常采用。在游戲中同步的是玩家的操作指令&#xff0c;操作指令包含當前的幀索引。一般的流程是客戶端上傳操作到服務器&#xff0c; 服務器收到后并不計算游戲行為&#xff0c; 而是轉發到所有客戶端。這里最重要的…

幀同步和狀態同步(二)案例分析

轉自&#xff1a;http://www.gameres.com/489361.html 騰訊一下出了兩款MOBA游戲&#xff0c;全民超神&#xff0c;王者榮耀&#xff0c;玩了一下&#xff0c;效果不錯&#xff0c;就分析了一下它底層的一些技術&#xff0c;發現一個是采用的狀態同步&#xff0c;TCP協議&#…

leetcode279 完全平方數

給定正整數 n&#xff0c;找到若干個完全平方數&#xff08;比如 1, 4, 9, 16, ...&#xff09;使得它們的和等于 n。你需要讓組成和的完全平方數的個數最少。 示例 1: 輸入: n 12 輸出: 3 解釋: 12 4 4 4. 示例 2: 輸入: n 13 輸出: 2 解釋: 13 4 9. 思路&#xf…