Java 并发——volatile

Java 并发——volatile
JVM内存管理

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

内存模型
  图如篇首。
  首先我们应该明白CPU是执行命令的场所,当需要处理数据时,CPU会从主内存(计算机内存)中取值,这样很慢。后来有了CPU高速缓存(cache),也就是CPU上有一小块存储空间缓存了从主内存中获取的数据,CPU直接读取cache,效率大增。
  然后,问题出现了,待处理的数据并非是主内存中的原型,而是一个副本,在多线程场景下,这个副本的处理结果很有可能会失控。这个问题也就是缓存一致性问题,即cache和主内存数据同步问题。目前我知道解决缓存一致性问题有两种方案:

通过在总线加LOCK锁
通过缓存一致性协议
  第一种是通过独占CPU方式实现,同一时间只有一个CPU在运行,效率低下。
  第二种允许多核处理,并且让共享副本在线程之间具有可见性。

可见性
  通过 volatile 实现了缓存一致性,其工作原理如下:
Java 并发——volatile
当某个CPU在写数据时,如果发现操作的变量是共享变量,则会通知其他CPU告知该变量的缓存行是无效的,因此其他CPU在读取该变量时,发现其无效会重新从主存中加载数据。

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

非原子性
  线程内存与主内存的交互过程如下:
Java 并发——volatile
主要有以下5项操作:

read:从主内存中读取变量
load:复制变量到线程本地内存作为副本
use:运算副本
assign:给副本赋值
store:副本写入线程本地内存
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 不能解决并发计算问题

猜你喜欢

转载自blog.51cto.com/13917525/2320095