volatile关键字用于当多个线程进行操作时的数据共享,可以保证内存中的数据是相互可见的,即线程可见性;
功能相似的static关键字则用于实例间的数据共享,是类的静态成员,与线程无关。
相较于synchronized关键字,volatile关键字是较为轻量级的同步策略,不具备互斥性,也不能保证原子性。
public class Volatile {
//(1)(2)
static volatile int num = 0;
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
//(3)(4)
num = 1;
//(5)(6)
System.out.println("t1 before:"+num);
try {
//线程休眠1秒,等待其他线程修改参数
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//(13)(14)
//本线程的num被修改
System.out.println("t1 after:"+num);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
//(7)(8)
System.out.println("t2 before:"+num);
//(9)(10)
num = 2;
//(11)(12)
System.out.println("t2 after:"+num);
}
}).start();
// 输出:
// t1 before:1
// t2 before:1
// t2 after:2
// t1 after:2
}
}
其中线程t1中的num被t2修改,代码中变量num在线程中数据变换流程如下图(原理可参考Java内存模型JMM):
步骤顺序及说明:
(1)(2):主线写入变量num为0到线程工作内存,并同步到主内存,此时主内存num=0;
(3)(4):线程t1将工作内存中的num改为1,并同步到主内存,此时主内存num=1;
(5)(6):线程t1读取num,先从主内存同步到线程工作内存中,线程t1中num=1;
(7)(8):线程t2读取num,先从主内存同步到线程工作内存中,线程t2中num=1;
(9)(10):线程t2修改num为2,并同步到主内存,此时主内存num=2;
(11)(12):线程t2读取num,先从主内存同步到线程工作内存中,线程t2中num=2;
(13)(14):线程t1读取num,先从主内存同步到线程工作内存中,线程t1中num=1;
其中线程1和线程2为并行线程,执行顺序可能与上面的不一致。