【多執行緒與高併發 2】volatile 篇
多執行緒與高併發 2
volatile 篇
偏向鎖 -> 迴圈鎖 -> 重量級鎖
synchronized(只能使用Object)
當執行緒≥2時,自旋鎖;當自旋次數>10時,重量級鎖。
Lock( )
CAS使用自旋
synchronized( )
使用鎖升級
volatile // 可變的,易變的
保證執行緒可見性,禁止指令重排序。
保證執行緒可見性:一個類的值給兩個類同時呼叫,裡面的變數改變後無法輕易發現(執行緒之間不可見)。
volatile可以讓一個執行緒發生改變之後,另一個執行緒可以馬上知道。
// 原理:CPU的快取一致性協議。
禁止指令重排序:CPU迸發執行指令,所以會對指令重新排序,加了volatile來保證重排序。
單例:保證在JVM記憶體永遠只有某一個類的一個例項(比如:許可權管理者)。
- 餓漢式:(定義類的時候就例項化方法)
public class Mgr01{
private static final Mgr01 INSTANCE = new Mgr01();
private Mgr01(){};
public static Mgr01 getInstance(){return INSTANCE;}
public void m() {System.out.println("m");}
public static void main(String[] args){
Mgr01 m1 = Mgr01.getInstance();
Mgr01 m2 = Mgr01.getInstance();
System.out.println(m1 == m2);
}
}
- 懶漢式:什麼時候呼叫方法什麼時候初始化
public class Lazy{
private Lazy(){}
//預設不會例項化,什麼時候用什麼時候new
private static Lazy lazy=null;
public static synchronized Lazy getInstance(){
if(lazy==null){
lazy=new Lazy();
}
return lazy;
}
}
餓漢式 | 懶漢式 | |
---|---|---|
安全 | √ | |
節省記憶體 | √ |
- 懶漢餓漢合併:
類的定義:
public class Mgr01{ private /*volatile*/ static Mgr0x INSTANCE; private Mgr0x(){}; public static Mgr01 getInstance(){ //以下所有程式碼寫的都是這一個方法 } }
以下所有方法寫的都是上面的
getInstance()
方法。以上方法沒有加
volatile
,最後會寫上。
- 直接判斷null
// 先判斷是否為空 然後再那啥: public static Mgr03 getInstance(){ if(INSTANCE == null){ try{ Thread.sleep(1); }catch(InterruotedException e){ e.printStackTrace(); } INSTANCE = new Mgr03(); } return INSTANCE; }
↑ ↑ ↑ ↑ ↑ 這是一種錯誤的書寫方式,自己抿;
- 先鎖再null
public static synchronized Mgr04 getInstance(){ if(INSTANCE == null){ try{ Thread.sleep(1); }catch(InterruotedException e){ e.printStackTrace(); } INSTANCE = new Mgr04(); } return INSTANCE; }
↑ ↑ ↑ ↑ ↑ 修改正確,但是違背了 能不加鎖就不加鎖 原則。
- 鎖細化:
public static Mgr05 getInstance(){ if(INSTANCE == null){ synchronized (Mgr05.class){ try{ Thread.sleep(1); }catch(InterruotedException e){ e.printStackTrace(); } INSTANCE = new Mgr05(); } } return INSTANCE; }
↑ ↑ ↑ ↑ ↑ 這也是一種錯誤的書寫方式(重複初始化);
- 雙重檢查:
public static Mgr05 getInstance(){ if(INSTANCE == null){ synchronized (Mgr05.class){ if(INSTANCE == null){ try{ Thread.sleep(1); }catch(InterruotedException e){ e.printStackTrace(); } INSTANCE = new Mgr05(); } } } return INSTANCE; }
↑ ↑ ↑ ↑ ↑ 修改正確…而且鎖不載入外面,效率增高~~
- 關於
volatile
(主要是指令重排序
)超高超高迸發的情況可能會發生:// new物件的三步 INSTANCE = new Mgr06(); 1. 申請記憶體並給初始值(int = 0,String = null;) 2. 修改值 3. 將值給物件
加
volatile
防止第二步第三步會顛倒;
- 一個求結果是 100000 的小程式
public class T{ volatile int count = 0; // 加上vilatile synchronized void m(){ // 加上 synchronized for(int i=0;i<10000;i++){count++;} } public static void main(String[] args){ T t = new T(); List<Thread> threads = new ArraysList<~>(); for(int i=0;i<10;i++){ threads.add(new Thread(t::m,"threads-"+i)); } threads.forEach((o)->o.start()); threads.forEach((o)->{ try{ o.join(); } catch(InterruptedException e){ e.printStackTrace(); } }); System.out.println(t.count); } }
只有加上了 synchronized & volatile 才能執行出正確結果,其中 synchronized 用來保證
原子性
。
鎖優化
- 鎖力度變小(爭用不是很激烈的話)
如果有一群要爭用的程式碼,那麼可以將方法上的 synchronized 寫到 count++ 上;
- 鎖力度變大(爭用很激烈很頻繁的話)
假如一個方法裡面 總共 20 行程式碼,加了19行,那不如直接用一個大的鎖。
鎖的物件被呼叫
public class = T{
Object o = new Object();// 錯誤修改點
synchronized(0){
sout("123");
}
public void zbc(){
T t = new T();
t.o = "a";
}
↑ ↑ ↑ 以上程式碼錯誤!以下為修改 ↓ ↓ ↓
final Object o = new Object();
有些類在建立的時候直接加了鎖
Atomic 開頭的 (
AtomicInteger count = new AtomicInteger( );
// 讓count進行原子性加減)
CAS ( Compare And Set ) 無鎖優化 樂觀鎖
在請求的時候就樂觀的認為 程式碼裡的值就是我的期望值
cas (V ,Expected,NewValue){
if (V == Expected){
V = NewValue;
}else{
tryAgain or fail;
}
}
↑ ↑ ↑ 以上是在CPU 原語上的支援,不能被打斷。
ABA
問題(與前女友複合之後,其實她已經經歷了n個
男人;)
有個物件 object == 1;想使用cas
把它變成2:
cas(object,1,2);//沒有執行緒進行操作,可以進行更改
如果在更改的時候有一個執行緒給 object 改成了2,然後又改成了 1 ;在基礎型別(如:int)沒有影響,但是 Object
物件有影響;
解決方法:做 cas
的時候加個版本號:version
解決方法:使用 AutomicStampedReference ( unsafe 什麼時候呼叫什麼時候返回這個值 )
相關文章
- 【多執行緒與高併發】- 淺談volatile執行緒
- 多執行緒與高併發(二)執行緒安全執行緒
- 多執行緒與高併發(一)多執行緒入門執行緒
- 【多執行緒與高併發】- 執行緒基礎與狀態執行緒
- java多執行緒與併發 - volatile的作用及原理Java執行緒
- Java高併發與多執行緒(一)-----概念Java執行緒
- 多執行緒併發篇——如何停止執行緒執行緒
- 深入理解Java多執行緒與併發框(第⑦篇)——volatile 關鍵字Java執行緒
- Java多執行緒/併發09、淺談volatileJava執行緒
- JUC之Exchanger-多執行緒與高併發執行緒
- 分散式叢集與多執行緒高併發分散式執行緒
- Java高併發與多執行緒(二)-----執行緒的實現方式Java執行緒
- 多執行緒與高併發(三)synchronized關鍵字執行緒synchronized
- 【多執行緒與高併發3】常用鎖例項執行緒
- 併發與多執行緒之執行緒安全篇執行緒
- 【多執行緒與高併發】從一則招聘資訊進入多執行緒的世界執行緒
- 【多執行緒與高併發原理篇:3_java記憶體模型】執行緒Java記憶體模型
- 併發與多執行緒基礎執行緒
- 多執行緒與併發----Semaphere同步執行緒
- java多執行緒與併發 - 併發工具類Java執行緒
- java多執行緒與併發 - 執行緒池詳解Java執行緒
- 多執行緒與高併發(五)final關鍵字執行緒
- 分散式、高併發與多執行緒有何區別分散式執行緒
- Java面試之多執行緒&併發篇(2)Java面試執行緒
- 多執行緒高併發解決辦法執行緒
- Java高併發與多執行緒(三)-----執行緒的基本屬性和主要方法Java執行緒
- 併發程式設計之volatile與JMM多執行緒記憶體模型程式設計執行緒記憶體模型
- 深入理解Java多執行緒與併發框(第①篇)——執行緒的狀態Java執行緒
- 深入理解Java多執行緒與併發框(第⑪篇)——執行緒池引數Java執行緒
- 多執行緒併發篇——三件兵器執行緒
- 多執行緒與併發----讀寫鎖執行緒
- 你分得清分散式、高併發與多執行緒嗎?分散式執行緒
- 分散式、高併發與多執行緒、你分辨的清嗎?分散式執行緒
- Java多執行緒——volatileJava執行緒
- JAVA多執行緒併發Java執行緒
- Java多執行緒/併發06、執行緒鎖Lock與ReadWriteLockJava執行緒
- Java進階篇:多執行緒併發實踐Java執行緒
- Nginx 高階篇(十)並行 併發 單執行緒(廢話篇 )Nginx並行執行緒