把java基礎擼一邊,從簡單的開始。
執行緒部分:
對synchronize初步瞭解之後,知道大概原理暫時先放下,其他深入的後續再來(原因是我也還不會)。本章是對java提供的另一個關鍵字volatile認識一下,並使用它。
volatile 單詞意思:adj. [化學] 揮發性的;不穩定的;爆炸性的;反覆無常的
n. 揮發物;有翅的動物
我理解為是個可變的意思,不穩定。
可見性
在多執行緒開發中,對共享資料的操作是會有頻繁操作的,為了保證在開發中,對會頻繁變動的多執行緒運算元據保證一致性。java提供了synchronize,還有volatile。
在瞭解之前,知道一個詞:可見--一個執行緒修改了這個變數,在另一個執行緒中能夠讀到這個修改後的值。這裡注意一下,只是讀到,而不是讀寫操作。不能保證原子性
synchronize是在保護他的程式碼塊,不被同時兩個執行緒進入操作出現,讓執行緒是序列進入。重而保證了這個可見性。
volatile是怎麼樣保證引數的可見呢?
這裡直接講原理會好點:在建立例項的時候,加了volatile修飾詞的話,在彙編中會多了一個lock指令。
lock指令:
在多處理器的系統上,1:將當前處理器快取行的內容寫回都系統記憶體
2:這個寫回記憶體的操作會使其他CPU裡的快取了該記憶體地址的資料失效
可以理解為volatile是讀鎖。在記憶體int a 的資料被執行緒1影響到了CPU執行緒2快取的int i的資料,但注意。這裡只相信讀到的資料。但不影響執行緒2執行緒3這個共享記憶體的資料操作。這樣也就可以知道,這個volatile的侷限性。它不具備原子性,只有可見性。及時更新,但不限制其他資料退volition修飾的操作。
對於他的侷限性。執行做如下操作
例項:
對一先修飾也volition的資料,程式只執行一方進行操作,其他執行緒不允許進行更改,只可以讀。這也是叫輕量級鎖的原因。下面展示程式碼
public class A3 {
private volatile int a ;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}複製程式碼
public class Demo31 {
public static void main(String[] age ){
A3 a3 = new A3();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0 ; i <= 100 ; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "修改值"+i);
a3.setA(i);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0 ; i <= 100 ; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "讀取值"+a3.getA());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0 ; i <= 100 ; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "讀取值"+a3.getA());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0 ; i <= 100 ; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "讀取值"+a3.getA());
}
}
}).start();
}
}複製程式碼
Thread-0修改值0
Thread-1讀取值0
Thread-2讀取值0
Thread-3讀取值0
Thread-0修改值1
Thread-1讀取值1
Thread-2讀取值1
Thread-3讀取值1
Thread-0修改值2
Thread-1讀取值2
Thread-2讀取值2
Thread-3讀取值2
Thread-0修改值3
Thread-1讀取值3
Thread-2讀取值3
Thread-3讀取值3
Thread-0修改值4
Thread-1讀取值4
複製程式碼
可以看到,一旦執行緒被修改之後,讀取到的資料就不會更改過來。但如果同時對資料進行修改
public class Demo31 extends Thread {
public volatile int a = 0 ;
public void set(){
for (int i = 0 ; i < 100 ; i++){
a++;
System.out.println(Thread.currentThread().getName() + " a : "+a);
}
}
@Override
public void run() {
set();
}
public static void main(String[] age ){
new Demo31().start();
new Demo31().start();
new Demo31().start();
}
}複製程式碼
結果
Thread-0 a : 1
Thread-1 a : 1
Thread-1 a : 2
Thread-0 a : 2
Thread-1 a : 3
Thread-2 a : 1
Thread-1 a : 4
複製程式碼
即使被volatile修飾之後,但並不會保證原子性。對於volatile的操作。要儘量保證是一個執行緒修改,其他執行緒只是讀。
推薦文章: