volatile作用
强制线程从公共堆栈中取得变量的值,而不是从线程私有变量中取值,解决变量在多线程之间读取的可见性。具有可见性,可是不具备原子性
synchronized作用
保证多个线程资源的同步,具有可见性和原子性,可以保证线程安
线程安全2个特点
- 原子性:执行过程中,不会被其他线程打扰
- 可见性:一个线程修改状态,对其他线程而言是可见的
volatile原理
每个线程访问堆中对象时,将堆中对象load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆变量值有任何关系,而是直接修改副本变量值。
修改完之后,自动把线程变量副本的值写到对象在堆变量中。这样堆中对象的值就产生了变化。这些操作不是原子性的。
使用volatile修饰变量,JVM只是保证从内存加载到线程工作内存中的值是最新的。因此,即使使用volatile还是会存在并发情况。
比如:
- volatile static int a=0;
线程A和线程B同时执行 - a++;
此时线程A拿到a的最新值0,线程B也拿到最新值0;但是,A执行a++后,值为1,B也同样计算得到a=1,它们再同时写回到堆内存,使得最后a的值为1,并不为2.
模拟代码如下:
public class Demo {
public volatile static int count =0;
@org.junit.Test
public void Test(){
for (int i = 0; i < 1000; i++) {//创建1000个线程执行
new Thread(new Runnable() {
@Override
public void run() {
doCount();
}
}).start();
}
System.out.println(Demo.count);
}
public void doCount(){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
结果会在0~1000之内摇摆不定,原因不用多说。所以,volatile不能保证数据的安全性,只能保证线程从堆中读取的是最新数据而已。
参考地址:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html
网友评论