展开全部
你误解了volatile的用法,volatile和原子性、非原子性没有任何关系,用volatile修饰的变量,线程在每次使用变量的时候,32313133353236313431303231363533e58685e5aeb931333431346335都会读取变量修改后的最新的值,注意,只是读取。我写了一个例子,方便你理解:public class Counter {
public volatile static int i = 0;
public static void inc() {
i++;
}
public static void main(String[] args) {
// 同时启动1000个线程,去进行i++计算,看看实际结果
for (int i = 0; i
new Thread(new Runnable() {
@Override
public void run() {
Counter.inc();
}
}).start();
}
// 这里每次运行的值都有可能不同,可能为1000
System.out.println("运行结果:i.count=" + Counter.i);
}
}
运行结果:运行结果:i.count=965
这里的结果并不是我们所预期的1000,那么问题究竟出在哪里?
假如,现在 i = 100,线程A和线程B同时读取了 i,那么线程A和线程B中的 i 都是100。然后,线程A执行了 i++ 操作,此时 i = 101,这里注意,线程B中的 i 不会受到线程A执行完后的影响,还是等于100,线程B执行i++ 操作,此时 i = 101。
为什么线程A中的 i 不会对线程B中的 i 造成影响?
这里就涉及到内存的知识了,最开始定义的全局变量 i 是储存在主内存中的,而每一个线程运行时都有一个线程栈。当线程访问 i 的时候,首先找到堆内存的变量 i,然后把堆内存变量 i 的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和堆内存变量 i 有任何关系,而是直接修改副本变量的值。在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到堆中变量。这样在堆中 i 的值就产生变化了。