volitale最经典理解

  • volatile跟Java的内存模型有关,非volatile变量时,平常情况,线程执行时会将变量从主内存加载到线程工作内存,建立一个副本,在某个时刻写回。
  • valatile指的每次都读取主内存的值,有更新则立即写回主内存。
  1. “volatile保证了线程之间的可见性”:因为线程看到volatile变量会去读取主内存最新的值,而不是自个一直在那跟内部的变量副本玩,所以保证了valatile变量在各个线程间的可见性。
    1. “volatile保证了线程之间的可见性”:因为线程看到volatile变量会去读取主内存最新的值,而不是自个一直在那跟内部的变量副本玩,所以保证了valatile变量在各个线程间的可见性。
      1. “volatile保证了线程之间的可见性”:因为线程看到volatile变量会去读取主内存最新的值,而不是自个一直在那跟内部的变量副本玩,所以保证了valatile变量在各个线程间的可见性
        1. “volatile保证了线程之间的可见性”:因为线程看到volatile变量会去读取主内存最新的值,而不是自个一直在那跟内部的变量副本玩,所以保证了valatile变量在各个线程间的可见性。
作者:陈美芳
链接:https://zhuanlan.zhihu.com/p/28324074
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我们都知道线程是在寄存器中运行的,而变量是保存在内存中的,当线程需要使用普通变量时会把变量copy一份到寄存器中,然后进行(多次)使用、修改等操作,完成之后再将更新后的变量写到内存中。但是在线程对变量副本进行修改等操作时,内存中变量的变化对于该线程是不可见的,这种行为是线程不安全的。笔者截取了一小段代码为例来说明这个问题:

public class CThread extends Thread {
    private OutputStream ous;
    static  boolean flag=true;

	public CThread(OutputStream ous) {
		super();
		this.ous = ous;
	}


	@Override
	public void run(){
		while(flag){
			Scanner c=new Scanner(System.in);
			try {
				ous.write((c.nextLine()+"
").getBytes());
				ous.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}


}

在主函数中启动线程后将flag的值修改为false,线程很有可能继续运行。这是因为主函数中对变量flag的操作对线程不可见。即线程已经拷贝了一份flag的信息(拷贝时flag为true),然后在寄存器里进行一系列操作,当内存更新后线程不知道,仍然以副本中flag的值(true)在运行。

而volatile修饰的变量具有可见性,即保证线程读取到的是最新更新的值。线程不拷贝内存变量而是直接读取内存中的变量,当内存中变量被其他线程修改后线程能立马知道。volatile是比同步更轻量级的操作,同步是锁定变量,只允许一个线程对其进行操作,是原子性动作。

当然被volatile修饰的变量也不是绝对的线程安全的。

public class Test extends Thread{
	private volatile static  int count=0;
	 public static void main(String[] args) {
		 Test t= new Test();
		 t.test();
		 System.out.println(count);
	 }

	 public void test(){

		 for(int i=0;i<1000;i++){
			 new Test().start();
		 }

	 }

	 @Override
	 public void run(){
		 try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

			count++;
	}

}

我运行的结果是:999

为什么不是理论上的1000呢?

假设count在内存中最新更新的值是666,才是a线程和b线程都读取了这个变量的值然后分别进行加1的操作,a更新内存的值为667,b也更新内存的值为667,这就导致了线程不安全。

原文地址:https://www.cnblogs.com/panxuejun/p/8622194.html