对于volatile关键字,大家都很熟悉,字面意思也比较简单,线程共享,每个线程都能读取到主内存的最新数据,但真的用好就不是那么简单的事,为什么需要volatile来线程共享?又为什么线程读取的不是最新的数据而需要volaile来实现呢?volatile能不能保证线程安全呢?
首先要理解线程安全是什么,当不同的线程在并发运行的时候,修改的数据在不同的线程显示不同的数据,发生脏读,比如a线程修改了张三的金额从100-10=90,而b线程获取的张三金额还是100,这时候就出现了脏读,多线程个线程导致了线程不安全。Jvm虚拟机内存模型规定所有变量都存在主内存中(类似于计算机的物理内存),为了高效性,每个线程都有自己的内存,所以线程对变量的操作都会在自己工作内存中运行,因此多个线程处理一个共享变量的时候,这时候就会出现线程安全问题。
其实这时候就能想到了thredLocal,作用就是保证在多线程的情况下,每个线程都可以处理自己独立的变量,存储在自己独立的map中,那么既然java线程既然本身就是在线程独立内存运行的,为何多此一举又出现了threadLocal,这就是上面说的,为了解决多个线程处理同一个共享变量时候出现的线程不安全问题。
言归正传,volatile有三个重要的特性,可见性,有序性,线程不安全性,如果大家吧前面的看完之后,基本就可以理解可见性了,可见性就是线程在处理变量的时候,不会从自己的内存中获取,而是才能够java堆里面获取其他线程也会改变的量,这个量也可以称为最后值,永远是最新的,而有序是保证他不会重新排序,java会对有延迟的代码进行重新排序,在不影响结果的情况下,效率块的代码会放到前面执行,但volatile会保证代码不会重排序。线程是否安全呢,答案是否定的,他能保证可见性和有序性,但是不能保证原子性,因为java里的运算是非原子的,比如jvm处理一个变量需要先load到线程栈中,然后在线程栈中改变值,最后在线程退出的时候,才会改变java堆的值,这些操作不会保证原子性,synchronized可以保证原子性,说明他和synchronized不同的是,线程非安全的。
那么他可以保证线程安全吗,如果保证两点,一就是运算的结果不依赖变量的最新值,或者保证只有一个线程才能改变那个值,也就是变量值不会共享,二就是变量不需要与其他状态变量共同参与不变约束。
讲到这里就解释完了,如果有什么意见或者不对的地方,欢迎提出评论,或者与本人私聊商讨。