Java 并发——volatile

JVM内存管理JVM内存管理

概述

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

内存模型

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

  1. 通过在总线加LOCK锁
  2. 通过缓存一致性协议

  第一种是通过独占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:副本写入线程本地内存
  • write:线程内存中的共享副本刷新主内存中的共享变量

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

  网友解答:

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

package com.zhoupq.multiThread.Volatile;
public class VolatileDemo implements Runnable
{
	static volatile int	i	= 1;
	@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 不能解决并发计算问题

在这里给大家提供一个学习交流的平台,java交流群: 558787436

具有1-5工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加群。

在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加群。

如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的可以加群。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值