voliate关键字
1 使变量在线程间可见
对于避免不可见性问题,Java还提供了一种弱形式的同步,即使用了volatile关键字。该关键字确保了对一个变量的更新对其他线程可见。当一个变量被声明为volatile时候,线程写入时候不会把值缓存在寄存器或者或者在其他地方,当线程读取的时候会从主内存重新获取最新值,而不是使用当前线程的拷贝内存变量值。volatile虽然提供了可见性保证,但是不能使用他来构建复合的原子性操作,也就是说当一个变量依赖其他变量或者更新变量值时候新值依赖当前老值时候不在适用。与synchronized相似之处在于如图
如图线程A修改了volatile变量b的值,然后线程B读取了改变量值,那么所有A线程在写入变量b值前可见的变量值,在B读取volatile变量b后对线程B都是可见的,图中线程B对A操作的变量a,b的值都可见的。volatile的内存语义和synchronized有类似之处,具体说是说当线程写入了volatile变量值就等价于线程退出synchronized同步块(会把写入到本地内存的变量值同步到主内存),读取volatile变量值就相当于进入同步块(会先清空本地内存变量值,从主内存获取最新值)。
转自http://ifeve.com/%E9%AB%98%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E5%BF%85%E5%A4%87%E5%9F%BA%E7%A1%80/
/**
* Created by lixiaodong on 2017/6/23.
*/
public class Test extends Thread{
//voliate
private String i ="sss";
private void setI(String i){
this.i=i;
}
@Override
public void run() {
System.out.println("进入方法"+i);
while (i.equals("sss")){
// System.out.println("方法执行");
//
// try {
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
System.out.println("线程结束");
}
public static void main(String[] args ) throws InterruptedException{
Test test=new Test();
test.start();
Thread.sleep(1000);
System.out.println("线程设置了stop");
test.setI("线程设置了stop");
}
}
上面是一个简单的示例。
- 首先运行代码,可以看到,尽管将变量设置了stop,test线程并没有如预期的停止.说明,test线程内的i的并没有被修改,test只是在start时将i变量拷贝到了线程自有的一块空间内,与主线内的i变量互不影响.
- 将voliate关键字放在变量i的声明上,运行发现程序正常停止.可见变量i在任何一个线程内都是可见的,当变量i在主线程被修改时,子线程立即获得了被更新的值.
- 最坑的地方来了,打开代码中的while循环中的打印语句,将voliate关键字注释掉,执行代码.神奇的事情发生了,程序正常的停止了,WTF!(在我最开始研究voliate的时候,我一直有这句输出语句,一直得不到正确结果)这是为啥呢?下面这段话基本说明了问题,同时你也可以将输出语句注释点,打开sleep的注释,看看结果.
网友评论