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);
}
}
输出结果: