美文网首页
Java 并发——volatile

Java 并发——volatile

作者: 4a873e424089 | 来源:发表于2018-11-21 20:03 被阅读0次

    JVM内存管理

    概述

    volatile 是轻量级的 synchronized。volatile 作用于共享变量,具备了“锁”的特性,这是为了确保共享变量能被准确和一致性地更新,这是 volatile 的可见性。同时,它也阉割了 scnchronized 的一写功能,比如:原子性。

    内存模型

    图如篇首。

    首先我们应该明白CPU是执行命令的场所,当需要处理数据时,CPU会从主内存(计算机内存)中取值,这样很慢。后来有了CPU高速缓存(cache),也就是CPU上有一小块存储空间缓存了从主内存中获取的数据,CPU直接读取cache,效率大增。

    然后,问题出现了,待处理的数据并非是主内存中的原型,而是一个副本,在多线程场景下,这个副本的处理结果很有可能会失控。这个问题也就是缓存一致性问题,即cache和主内存数据同步问题。目前我知道解决缓存一致性问题有两种方案:

    通过在总线加LOCK锁

    通过缓存一致性协议

    第一种是通过独占CPU方式实现,同一时间只有一个CPU在运行,效率低下。

    第二种允许多核处理,并且让共享副本在线程之间具有可见性。

    可见性

    通过 volatile 实现了缓存一致性,其工作原理如下:

    当某个CPU在写数据时,如果发现操作的变量是共享变量,则会通知其他CPU告知该变量的缓存行是无效的,因此其他CPU在读取该变量时,发现其无效会重新从主存中加载数据。

      volatile 的可见性只针对当CPU从主内存中加载共享变量的时候。但是当线程A、B同时加载了共享变量i,后者说线程A先加载了i,在A将i写入之前,B加载了i,B加载的i仍然是主内存中i的初始值。

    非原子性

    线程内存与主内存的交互过程如下:

    主要有以下5项操作:

    read:从主内存中读取变量

    load:复制变量到线程本地内存作为副本

    use:运算副本

    assign:给副本赋值

    store:副本写入线程本地内存 直播系统开发找上海捌跃网络科技有限公司 17621291122

    write:线程内存中的共享副本刷新主内存中的共享变量

    上一章节——“可见性”中已经声明 volatile 的可见性只针对当CPU从主内存中加载共享变量的时候,即load之前,一旦load,无论主内存中的共享变量发生了什么,副本的值不会被主内存同步。也就是说,volatile不具有原子性。

      网友解答:

    volatile的非原子性:线程工作内容中的值从主内存中直接加载,一旦加载完成,就不会再产生对应的变化。JVM保证的是从主内存中加载到线程工作内存中的值是最新的,但是无法保证原子性。 volatile解决的是变量读时的可见性问题,无法保证原子性。

    package com.zhoupq.multiThread.Volatile;

    public class VolatileDemo implements Runnable

    {

    static volatile int i = 1;br/>@Override

    public void run()

    {

    System.out.println(Thread.currentThread().getName() + ": " + i + ", "

    (++i));

    }

    public static void main(String[] args)

    {

    Thread t1 = new Thread(new VolatileDemo(), "A");

    Thread t2 = new Thread(new VolatileDemo(), "B");

    Thread t3 = new Thread(new VolatileDemo(), "C");

    Thread t4 = new Thread(new VolatileDemo(), "D");

    t1.start();

    t2.start();

    t3.start();

    t4.start();

    }

    }

    /

    A: 1, 2

    B: 1, 3

    C: 3, 4

    D: 4, 5

    /

    结果与预期不符,在预期的结果中,线程B应该加载的i是2,运算之后变成3。由此我们知道,volatile 不能解决并发计算问题。

      网友解答:

    i 和+(++i)是两条指令,会发生这种情况:

    假设当前i为1,线程A执行+i,线程B执行+i,然后线程A执行+(++i),这时i=2,然后线程B执行+(++i),这时i=3,线程A输出(1, 2),线程B输出(1, 3)。

    小结

    volatile 保证可见性

    volatile 不保证原子性

    volatile 不能解决并发计算问题

    转自:http://blog.51cto.com/13917525/2320095

    相关文章

      网友评论

          本文标题:Java 并发——volatile

          本文链接:https://www.haomeiwen.com/subject/dykhqqtx.html