學習筆記,僅供自己參考叨襟,如有不對歡迎指正
1.關于內存模型
CPU高速緩存:因為CPU的執(zhí)行速度要大于內存的讀寫速度老翘,如果任何時候數(shù)據(jù)操作直接與內存交互锻离,效率很低墓怀,所以出現(xiàn)了CPU高速緩存
。
CPU高速緩存的作用:程序執(zhí)行過程中虱朵,會將運算需要的數(shù)據(jù)從主存復制一份到CPU的高速緩存當中钓账,那么CPU進行計算時就可以直接從它的高速緩存讀取數(shù)據(jù)和向其中寫入數(shù)據(jù),當運算結束之后服协,再將高速緩存中的數(shù)據(jù)刷新到主存當中啦粹。
程序的原子性、可見性跳纳、有序性
- 原子性:指一個操作是不可以中斷的贪嫂,不會被線程調度機制打斷。
- 可見性:指當一個線程修改共享變量的值時斗塘,其他線程會立刻知道這個指的修改
- 有序性:指程序執(zhí)行的順序按照代碼的先后順序執(zhí)行餐曹。
禁止指令重排
Java語言提供了volatile
和synchronized
兩個關鍵字來保證線程之間操作的有序性
。
volatile關鍵字本身就包含了禁止指令重排序的語義
synchronized則是由“一個變量在同一個時刻只允許一條線程對其進行l(wèi)ock操作”這條規(guī)則獲得的,這個規(guī)則決定了持有同一個鎖的兩個同步塊只能串行地進入饱狂。
參考:https://www.cnblogs.com/guanghe/p/9206635.html
2.關于線程安全
-
為什么會有線程安全宪彩?
當多個線程同時訪問統(tǒng)一代碼(同一塊對內存)的時候,會產(chǎn)生數(shù)據(jù)混亂的情況俊柔。 -
如何保證線程安全?
1.對非安全的代碼進行加鎖控制物赶;
2.使用線程安全的類留晚;
3.多線程并發(fā)情況下,線程共享的變量改為方法級的局部變量 -
synchronized和Lock的使用错维、區(qū)別及底層實現(xiàn)
使用:都是對程序進行加鎖赋焕,用來同步化代碼塊,保證線程安全
區(qū)別:
synchronized:
1.加鎖不可以中斷
2.synchronized可以加在方法上隆判,也可以加在特定代碼塊中蜜氨,括號中表示需要鎖的對象。
lock:
1.首先他是一個接口埋哟,可以中斷
2.需要顯示指定起始位置和終止位置郎汪。
3.一般使用ReentrantLock類做為鎖,多個線程中必須要使用一個ReentrantLock類做為對象才能保證鎖的生效煞赢。
4.在加鎖和解鎖處需要通過lock()和unlock()顯示指出照筑。
5.一般會在finally塊中寫unlock()以防死鎖。
底層實現(xiàn):鎖的本質凝危,是對象內存堆中頭部的一部分數(shù)據(jù)蛾默。當線程獲得一個鎖,即是在鎖內存區(qū)域設置一些標志冬念。線程釋放鎖也是改變這些標記。** -
volatile的原理和使用方式
原理:volatile保證了新值能立即同步到主內存急前,并且通知其他cpu核心,你們緩存中的數(shù)據(jù)無效了,這樣所有cpu核心再想對該volatile變量操作首先會從主內存中重新拉取值叔汁,從而保證數(shù)據(jù)安全
使用方式:volatile只保證了程序的可見性,但是不具備原子性据块。使用volatile必須滿足下面兩個條件:
1.對變量的寫操作不依賴于當前值
2.該變量沒有包含在具有其他變量的不變式中另假。
**適用場景舉例:
VolatileSimpleUse 不是線程安全的,因為get和set方法都是在沒有同步的情況下進行的己莺。如果線程1調用了set方法戈轿,那么正在調用的get的線程2可能會看到更新后的value值,也可能看不到思杯。
public class VolatileSimpleUse {
private int value;
public int get(){
return value;
}
public void set(int value){
this.value = value;
}
}
解決方法很簡單色乾,將value聲明為volatile變量:
private volatile int value;