把java基礎擼一邊,從簡單的開始。
java
線程部分:緩存
對synchronize初步瞭解以後,知道大概原理暫時先放下,其餘深刻的後續再來(緣由是我也還不會)。本章是對java提供的另外一個關鍵字volatile認識一下,並使用它。bash
volatile 單詞意思:adj. [化學] 揮發性的;不穩定的;爆炸性的;反覆無常的
多線程
n. 揮發物;有翅的動物ide
我理解爲是個可變的意思,不穩定。ui
在多線程開發中,對共享數據的操做是會有頻繁操做的,爲了保證在開發中,對會頻繁變更的多線程操做數據保證一致性。java提供了synchronize,還有volatile。this
在瞭解以前,知道一個詞:可見--一個線程修改了這個變量,在另外一個線程中可以讀到這個修改後的值。這裏注意一下,只是讀到,而不是讀寫操做。不能保證原子性spa
synchronize是在保護他的代碼塊,不被同時兩個線程進入操做出現,讓線程是串行進入。重而保證了這個可見性。線程
volatile是怎麼樣保證參數的可見呢?code
這裏直接講原理會好點:在建立實例的時候,加了volatile修飾詞的話,在彙編中會多了一個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的操做。要儘可能保證是一個線程修改,其餘線程只是讀。
推薦文章: