多线程-volatile关键字

标签: volatile volatile线程安全 volatile原子性
5人阅读 评论(0) 收藏 举报
分类:
首先我们知道在java中内存的交互有以下几点。

Read Load 和 Store Write 两对操作不可分割。

Lock(锁定):作用于主内存的变量,他把变量标识为一个线程独占的状态。
UnLock(解锁) :作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
Read(读取):作用于主内存的变量,它把一个变量的值从主内存中读取到线程工作内存中,以便随后的load动作使用。
Load(载入):作用于工作内存中的变量,它把read操作从主内存中得到的变量值放入工作内存中的变量副本中。
Use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令将会执行这个操作。
Assign(赋值):作用于工作内存的变量,它把执行引擎接收到的值付给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
Store(存储):作用于工作内存的变量,它把工作内存中的一个变量的值传递到主内存中,以便随后的write操作使用。
Write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。

Java内存模型还规定了在执行上述8种基本操作必须满足如下规则:
  1. 不允许read和load。store和write操作之一单独出现。
  2. 不允许一个线程丢弃它最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。
  3. 不允许一个线程无原因的把数据从线程的工作内存同步回主内存。
  4. 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用了一个未被初始化的变量,换句话说,就是一个变量实施use、store操作之前,必须先执行过了assign和load操作。
  5. 一个变量在同一个时刻只允许一个线程对其进行lock操作,但lock操作可以被同一条操作重复执行多次,多次执行lock之后,只有执行相同次数的unlock操作,变量才会被解锁。
  6. 如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新load和assign操作初始化变量的值。
  7. 如果一个变量实现没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许去lock一个被其他线程锁定住的变量。
  8. 对一个变量执行unlock操作之前,必须先把此变量同步回主内存中。

如果要把一个变量从主内存复制到工作内存,就要顺序地执行read和load操作,如果把变量从工作内存同步回主内存,就要顺序地执行store和write操作。



volatile的作用是,能够保证变量对线程的可见性,也就是说,变量值被其中一个线程更改后对其他线程是可见的,但是并不能保证复合操作的原子性(例如i++)。所以要想保证线程安全,还需要通过其他的方式,例如synchronized关键字或者Lock锁。
如果需要对基本类型进行原子操作,可以使用基本类型的Atomic封装类。例如AtomicInteger,里面封装了一系列保证原子性的操作方法。   
 
volatile是如何保证变量对其他线程的可见性?
1、每次对变量的读操作都从主内存中获取。
2、每次对变量的写操作都第一时间写到主内存中。
并且volatile禁止指令的重排序,对在读之前和写之后加入一个内存屏障这样可以保证:一个线程写入一个变量后,任何线程都会得到最新值

happens-before中的一条
volatile域规则:对一个volatile域的写操作,happens-before于任意线程后续对这个volatile域的读。

可以通过一段代码来证明volatile是非线程安全的。


/**
* Created by kaijiyu on 2018/3/27.
*/
public class VolatileDemo {
    static volatile int x = 0;
    public static void add(){
        x++;
    }

    public static void main(String[] args) {

        for (int i = 0; i < 10; i++) {
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10000; j++) {
                        add();
                    }
                }
            });
            thread1.start();
        }
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(x);
    }

}
这段代码每次执行的结果都是不一样的,如果能够保证线程安全的话,x的值应该始终为100000;
如果要保证线程安全,只需要给add()方法加一个synchronized关键字即可。

volatile关键字有时候会被错误的理解,认为只要对变量使用volatile关键字就会确保线程安全,其实并不是,volatile只能起到一个简单的同步作用。

只有在以下两种情况下,才可以保证原子性。
1、运算结果不依赖变量的当前值,或者只有单一线程修改变量值
2、变量不需要和其他状态变量共同参与不变约束



查看评论

Python-多线程

-
  • 1970年01月01日 08:00

多线程---volatile关键字

在多线程中,volatile关键字是很重要的一个知识点,在多线程共享资源的时候,每个线程数据对外都是不可见的,这就容易出现”脏读”现象,其实就是线程私有堆栈中的数据和公共堆栈中的数据不同步造成的.解决...
  • baidu_17508977
  • baidu_17508977
  • 2016-12-22 15:50:21
  • 1890

Android线程—Volatile关键字(一)

一、基本概念 先补充一下概念:Java 内存模型中的可见性、原子性和有序性。 可见性:   可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。通常,...
  • weixin_37730482
  • weixin_37730482
  • 2017-06-09 14:09:51
  • 290

java多线程(四)关键字volatile

关键字volatile的主要作用是使变量在多线程间可见。       解决异步死循环       如下代码       public class RunThread extends Thread...
  • lxy344x
  • lxy344x
  • 2016-06-22 21:18:06
  • 686

关于多线程程序中使用volatile关键字的一个小例子

在公司分配给我的爬虫任务中,具体的信息又写需要在详情页中取得,所以需要在加入待抓取链接 我们用的框架是基于java 的webmagic ,这个框架可以在启动时设定多个线程抓取,所以待抓取的多...
  • qq_28352347
  • qq_28352347
  • 2017-01-20 19:42:19
  • 405

JAVA多线程-对象及变量的并发访问(二)volatile关键字

三、Volatile关键字     关键字volatile的主要作用是使变量在多个线程间可见。 3.1 关键字volatile与死循环 测试案例: 我想通过改变flag的值,从而停止对servi...
  • qq_26504875
  • qq_26504875
  • 2016-02-20 10:51:39
  • 1009

探究java多线程中正确的单例模式 volatile关键字

关键点是volite关键字的作用 单例模式的实现: 1.饿汉模式 public class Singleton { private static Singleton instance=new ...
  • glory1234work2115
  • glory1234work2115
  • 2016-03-06 21:24:33
  • 4284

c#中多线程修饰符volatile

volatile是C#中用于控制同步的关键字,其意义是针对程序中一些敏感数据,不允许多线程同时访问,保证数据在任何访问时刻,最多有一个线程访问,以保证数据的完整性,volatile是修饰变量的修饰符。...
  • lonestar555
  • lonestar555
  • 2015-10-10 16:05:44
  • 2240

Java线程安全之volatile关键字

我们知道在多线程的场景下,线程安全是必须要着重考虑的。Java语言包含两种内在的同步机制:同步块(synchronize关键字)和 volatile 变量。但是其中 Volatile 变量虽然使用简单...
  • Roy_70
  • Roy_70
  • 2017-04-07 10:37:02
  • 3808

多线程之volatile关键字

之前讲解了多线程的synchronized关键字,现在再学习一下volatile关键字。1 volatile关键字用来做什么?线程安全包括两个方面:原子性和可见性。Java的同步机制都是围绕这两个方面...
  • Trigl
  • Trigl
  • 2016-04-15 20:43:39
  • 1433
    个人资料
    持之以恒
    等级:
    访问量: 1514
    积分: 171
    排名: 103万+
    文章存档
    最新评论