synchronized -> 同步鎖
所有加上synchronized修飾的方法 或 代碼塊勋篓,在同一個時刻,只有一個線程能訪問
volatile -> 內(nèi)存可見性魏割,禁止指令重排序
對于volatile修飾的變量譬嚣,jvm虛擬機(jī)只是保證從主內(nèi)存加載到線程工作內(nèi)存的值是最新的.
如同上面所講的,volatile
只是保證從內(nèi)存加載到線程工作內(nèi)存的值是最新的钞它,那這里會出現(xiàn)什么問題呢拜银?無法保證操作的原子性
看一下代碼:
public class VolatileLearn {
public static int count = 0;
public static void add(){
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
count++;
}
public static void main(String[] args){
for (int i=0; i< 1000; i++){
new Thread(() -> {
VolatileLearn.add();
}).start();
}
try {
Thread.sleep(50000);
}catch (InterruptedException e){
e.printStackTrace();
}finally {
System.out.println("運(yùn)行的結(jié)果:count = " + VolatileLearn.count);
}
}
}
// 運(yùn)行的結(jié)果:count = 990
上面的例子中,自增操作是不具備原子性的遭垛,可分為: 讀取變量的原始值尼桶、進(jìn)行加1操作、寫入工作內(nèi)存锯仪,volatile
關(guān)鍵字只保證了讀取變量的原始值操作的原子性泵督,并沒有保證進(jìn)行加1操作、寫入工作內(nèi)存的原子性庶喜,也就是說會出現(xiàn)兩個線程讀取到的值(主內(nèi)存)相同小腊,線程對工作內(nèi)存操作后的結(jié)果一致,最后寫入主內(nèi)存只+1了久窟。
虛擬機(jī)在保證執(zhí)行結(jié)果準(zhǔn)確性的同時秩冈,會對指令進(jìn)行一定的重排,(來最大性能的發(fā)揮CPU瘸羡?)。
對于new Class來講搓茬,可以分為:
1)創(chuàng)建對象實(shí)例
2)執(zhí)行類的構(gòu)造函數(shù)
3)將實(shí)例對象指向分配的內(nèi)存空間
一般的執(zhí)行順序是1-2-3犹赖,也可能存在1-3-2這個順序,如果沒有volatile字段修飾卷仑,那可能存在某一個線程訪問獲取這個實(shí)例對象峻村,恰好執(zhí)行到1-3,這時候?qū)ο蟛]有執(zhí)行完構(gòu)造函數(shù)锡凝,是會出問題的粘昨。在這個實(shí)例對象的變量前添加volatile字段,可以避免指令被重排。
并發(fā)編程的三個概念:
- 原子性
- 可見性
- 有序性
更全面理解參考