多线程技术点二
1.Java線程之間的通信由Java內存模型控制(JMM)。
JMM定義了線程和主內存之間的抽象關系:線程之間的共享變量存儲在主內存中,每個線程都有一個私有的本地內存,本地內存中存儲了該線程以讀/寫共享變量的副本。
2.先行發生原則(happens-before)
3.數據依賴性
如果兩個操作訪問同一個變量,且這兩個操作中有一個為寫操作,此時這兩個操作之間就存在數據依賴性。
數據依賴分為3種類型:寫后讀,寫后寫,讀后寫
編譯器和處理器在重排序時,會遵守數據依賴性,編譯器和處理器不會改變存在數據依賴關系的兩個操作的執行順序。
4.as-if-serial語義
不管怎么重排序,(單線程)程序的執行結果不能被改變。
5.JMM和順序一致性模型的差異
1)順序一致性模型保證單線程內的操作會按照程序的順序執行,而JMM模型不保證單線程內的操作會按照程序的順序執行(臨界區內的重排序)
2)順序一致性模型保證所有線程只能看到一致的操作執行順序,而JMM不保證所有線程能看到一致的操作執行順序
3)JMM不保證對64位的long型和double型變量的寫操作具有原子性。
6.volatile關鍵字
可以把對volatile變量的單個讀/寫看成是使用同一個鎖對這些單個讀/寫操作做了同步。
volatile變量自身具有下列特性
1)可見性:對一個volatile變量的讀,總是能看到(任意線程)對這個volatile變量最后的寫入
2)原子性:對任意單個volatile變量的讀/寫具有原子性,但類似于volatile++這種復合操作不具有原子性
7.volatile寫-讀的內存語義
1)當寫一個volatile變量時,JMM會把該線程對應的本地內存中的共享變量值刷新到主內存
2)當讀一個volatile變量時,JMM會把該線程對應的本地內存置為無效。線程接下來將從主內存中讀取共享變量
8.重排序分為編譯器重排序和處理器重排序,為了實現volatile內存語義,JMM會分別限制這兩種類型重排序類型。為了實現volatile的內存語義,編譯器在生成字節碼時,會在指令序列中插入內存屏障來禁止特定類型的處理器重排序。
9.鎖的釋放和獲取的內存語義
當線程釋放鎖時,JMM會把該線程對應的本地內存中的共享變量刷新到主內存中。
當線程獲取鎖時,JMM會把該線程對應的本地內存置為無效。從而使得被監視器保護的臨界區代碼必須從主內存中讀取共享變量。
10.雙重檢查鎖定的問題根源
instance = new Singleton()這行代碼可以分解為如下3行偽代碼
memory=allocate();//分配對象的內存空間
ctorInstance(memory);//初始化對象
instance=memory;//設置instance指向剛分配的內存地址
解決方案:將instance聲明為volatile型,就可以實現線程安全的延遲初始化。
11.隊列同步器
用來構建鎖或者其他同步組件的基礎框架,它使用了一個int成員變量表示同步狀態,通過內置的FIFO隊列來完成資源獲取線程的排隊工作。
同步器的主要使用方式是繼承,子類通過繼承同步器并實現它的抽象方法來管理同步狀態,在抽象方法的實現過程中通過同步器提供的3個方法對同步狀態進行修改(getState()、setState(int newState)和compareAndSetState(int expect, int update))。
子類推薦被定義為自定義同步組件的靜態內部類。
12.同步器的設計是基于模板方法模式的,即使用者需要繼承同步器并重寫指定的方法,隨后將同步器組合在自定義同組組件的實現中,并調用同步器提供的模板方法。
13.同步器可重寫的方法:
protected boolean tryAcquire(int arg)——獨占式獲取同步狀態,實現該方法需要查詢當前狀態并判斷同步狀態是否復合預期,然后再進行CAS設置同步狀態。
protected boolean tryRelease(int arg)——獨占式釋放同步狀態,等待獲取同步狀態的線程將有機會獲取同步狀態。
protected int tryAcquireShared(int arg)——共享式獲取同步狀態,返回大于等于0的值,表示獲取成功,反之,獲取失敗。
protected boolean tryReleaseShared(int arg)——共享式釋放同步狀態
protected boolean isHeldExecusively()——當前同步器是否在獨占模式下被線程占用,一般該方法表示是否被當前線程所獨占。
14.隊列同步器的實現分析
1)同步隊列——
?同步隊列中的節點(Node)用來保存獲取同步狀態失敗的線程引用、等待狀態以及前驅和后繼節點。
同步器包含了兩個節點類型的引用,一個指向頭節點,而另一個指向尾節點。為了保證未能成功獲取同步狀態的線程加入同步隊列過程的線程安全性,同步器提供了一個基于CAS的設置尾節點的方法:compareAndSetTail(Node expect, Node update),它需要傳遞當前線程“認為”的尾節點和當前節點,只有設置成功后,當前節點才正式與之前的尾節點建立關聯。
節點進入同步隊列之后,就進入了一個自旋的過程,每個節點都在自省地觀察,當滿足條件,獲取到了同步狀態,就可以從這個自旋過程中退出。
2)獨占式同步狀態獲取與釋放
在獲取同步狀態時,同步器維護一個同步隊列,獲取狀態失敗的線程都會被加入到隊列中并在隊列中進行自旋;移出隊列(或停止自旋)的條件是前驅節點為頭節點且成功獲取了同步狀態。在釋放同步狀態時,同步器調用tryRelease(int arg)方法釋放同步狀態,然后喚醒頭節點的后繼節點。
3)共享式同步狀態獲取與釋放
共享式和獨占式獲取最主要的區別在于同一時刻能否有多個線程同時獲取到同步狀態。
轉載于:https://www.cnblogs.com/lvjygogo/p/8735171.html
總結
- 上一篇: MongoDB ( 五 )高级_索引
- 下一篇: 爬取校园新闻首页的新闻的详情,使用正则表