摘要:通過指令重排可以減少流水線停頓提升巨大效率原則程序順序原則一個線程內保證語義的串行性。鎖規則解鎖必然發生在隨后的加鎖前。線程的方法先于它的每一個動作。
1. 基本概念
同步(Synchronous)和異步(Asynchronous) 并發(Conncurrency)和并行(Parallelism) 臨界區 阻塞(Blocking)與非阻塞(Non-Blocking) 死鎖(Deadlock)、饑餓(Starvation)和活鎖(Livelock)
同步(Synchronous)和異步(Asynchronous)
并發(Conncurrency)和并行(Parallelism)
臨界區
臨界區:公共資源或共享數據,可被多個線程使用,但每次只能有一個線程使用,其他線程需等待
阻塞(Blocking)與非阻塞(Non-Blocking)
阻塞:一個線程占用了臨界區資源,其他線程就會在就必須在臨界區等待,等待會導致線程掛起,這就是阻塞
非阻塞:沒有一個線程可以妨礙其他線程執行,所有線程都會不斷嘗試向前
死鎖(Deadlock)、饑餓(Starvation)和活鎖(Livelock)
死鎖:A線程中占用a資源,并且嘗試去獲取b資源,同時B線程中占用著b資源,并且嘗試去獲取a資源,此時誰也無法進行下去,導致死鎖
饑餓:資源競爭激烈時,某個線程長時間無法獲取到資源,產生饑餓
活鎖:兩個線程競爭同一資源時相互謙讓,導致兩個線程一直在謙讓而無法正常工作
阻塞 無饑餓(Starvation-Free) 無障礙(Obstruction-Free) 無鎖(Lock-Free) 無等待(Wait-Free)
阻塞
使用synchronized關鍵字或重入鎖等時,會阻塞其他線程獲取臨界區資源
無饑餓(Starvation-Free)
使用公平鎖時,先到先得,不會產生饑餓;非公平鎖,由于競爭激烈,或者某些線程優先級高導致低優先級的線程有可能產生饑餓
無障礙(Obstruction-Free)
無障礙是最弱的非阻塞調度,兩個線程均可修改臨界區數據,一旦檢測到數據不安全,即對自己修改的數據進行回滾,確保數據安全,沖突嚴重時所有線程會不停回滾從而造成系統無法正常工作.
一般會配合"一致性標記"一起使用,操作前讀取一致性標記,修改后再次讀取此標記,若不一致則表示數據不安全
無鎖(Lock-Free)
無鎖的并行都是無障礙的.無鎖的并發必然有一個線程能夠在有限步內完成操作離開臨界區.一般都會包含無窮循環,且可能產生饑餓
無等待(Wait-Free)
無等待在無所的基礎上更進一步,要求所有線程必須在有限步內訪問完臨界區,這樣就不會引起饑餓問題
讀線程都是無等待的,寫數據時,采用RCU(Read Copy Update)策略,先取得原數據副本,再修改副本數據,修改完后在合適的機會寫回數據
JMM的技術點圍繞多線程的原子性、可見性和有序性來建立的
原子性(Atomicity)
32位虛擬機中操作long型變量是非原子性的,可能造成數據不安全
public class MultiThreadLong { public volatile static long t=0; public static class ChangeT implements Runnable{ private long to; public ChangeT(long to){ this.to=to; } @Override public void run() { while(true){ MultiThreadLong.t=to; //賦值臨界區的t Thread.yield(); //讓出資源 } } } public static class ReadT implements Runnable{ @Override public void run() { while(true){ long tmp=MultiThreadLong.t; if(tmp!=111L && tmp!=-999L && tmp!=333L && tmp!=-444L) System.out.println(tmp); //打印非正常值 Thread.yield(); //讓出資源 } } } public static void main(String[] args) { new Thread(new ChangeT(111L)).start(); new Thread(new ChangeT(-999L)).start(); new Thread(new ChangeT(333L)).start(); new Thread(new ChangeT(-444L)).start(); new Thread(new ReadT()).start(); //輸出: //-4294966963 //4294966852 //-4294966963 } }
可見性
可見性是指一個線程修改某一個共享變量的值時,其他線程是否能夠立即知道這個修改
原因:緩存優化或者硬件優化問題(內存讀寫不會立即觸發,而先進入一個硬件隊列);指令重排和編輯器的優化
有序性
并發時,程序的執行可能出現亂序,給人感覺就是:寫在前面的代碼,會在后面執行
public class OrderExample { int a=0; boolean flag=false; public void writer(){ a=1; flag=true; //這一步不一定在a=1之后 } public void reader(){ if(flag){ int i=a+1; //當flag=true時,a不一定為1,也可能未執行a=0 } } }
為什么要指令重拍呢? 完全是出于性能考慮,一條指令可以分為以下幾步: .取指IF。 ·譯碼和取寄存器操作數ID。 ·執行或者有效地址計算EX。 ·存儲器訪問MEM。 ·寫回WB。 通過指令重排可以減少cpu流水線停頓,提升巨大效率 Happen-Before原則: ·程序順序原則:一個線程內保證語義的串行性。 ·volatile規則:volatile變量的寫先于讀發生,這保證了volatile變量的可見性。 ·鎖規則:解鎖(unlock)必然發生在隨后的加鎖(lock)前。 ·傳遞性:A先于B,B先于C,那么A必然先于C。 .線程的start()方法先于它的每一個動作。 ·線程的所有操作先于線程的終結(Thread.join())。 ·線程的中斷(interrupt())先于被中斷線程的代碼。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/75926.html
摘要:探究系統登錄驗證碼的實現后端掘金驗證碼生成類手把手教程后端博客系統第一章掘金轉眼間時間就從月份到現在的十一月份了。提供了與標準不同的工作方式我的后端書架后端掘金我的后端書架月前本書架主要針對后端開發與架構。 Spring Boot干貨系列總綱 | 掘金技術征文 - 掘金原本地址:Spring Boot干貨系列總綱博客地址:http://tengj.top/ 前言 博主16年認識Spin...
摘要:實戰讀書筆記第一章從方法傳遞到接著上次的,繼續來了解一下,如果繼續簡化代碼。去掉并且生成的數字是萬,所消耗的時間循序流并行流至于為什么有時候并行流效率比循序流還低,這個以后的文章會解釋。 《Java8實戰》-讀書筆記第一章(02) 從方法傳遞到Lambda 接著上次的Predicate,繼續來了解一下,如果繼續簡化代碼。 把方法作為值來傳遞雖然很有用,但是要是有很多類似與isHeavy...
閱讀 1264·2021-09-23 11:51
閱讀 1370·2021-09-04 16:45
閱讀 626·2019-08-30 15:54
閱讀 2076·2019-08-30 15:52
閱讀 1594·2019-08-30 11:17
閱讀 3098·2019-08-29 13:59
閱讀 2010·2019-08-28 18:09
閱讀 381·2019-08-26 12:15