volatile關鍵字用於修飾簡單類型變量,如int、float、boolean等數據類型,保證同一時刻只能有一個線程修改變量。
volatile修飾變量的操作就會變成原子級別的,但這有一定的情況時效:
public class VolatileTEST {
volatile static int val = 0;
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(() -> {
for(int i=0; i<300000; i++){
val += 1;
}
});
Thread t2 = new Thread(() -> {
for(int i = 0; i<300000; i++){
val += 1;
}
});
long startTime = System.currentTimeMillis();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("時間:" + (System.currentTimeMillis() - startTime) + "毫秒");
System.out.println(val);
}
}
這個實例期望的是得到600000,但是實際運行結果:
原因是:val +=1 並不是原子操作。 當volatile修飾簡單變量,當前值是根據以前的值得到時,例如:val+=1,val=val+1 , val++等,volatile關鍵字將失效。只有當變量的值和以前的值無關時,對該變量的操作纔是原子級別,如val = n + 1。
這時候需要使用synchronized把操作(例如val+=1)抽取成一個方法:
public class VolatileTest2 {
static int val = 0;
public static synchronized void inc(){
val += 1;
}
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(() -> {
for(int i=0; i<300000; i++){
inc();
}
});
Thread t2 = new Thread(() -> {
for(int i = 0; i<300000; i++){
inc();
}
});
long startTime = System.currentTimeMillis();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("時間:" + (System.currentTimeMillis() - startTime) + "毫秒");
System.out.println(val);
}
}
輸出結果: