当前位置: 首页 > 知识库问答 >
问题:

Java volatile关键字

邰棋
2023-03-14

我知道关于volatile有很多问题,但我只是被讨论搞糊涂了:Java:volatile如何保证这段代码中“数据”的可见性?

我读过的每个网站都说可以在缓存中存储一个变量(使这个值对于其他线程不可见),我甚至发现了这个例子https://dzone.com/articles/java-volatile-keyword-0

所以我的第一个问题是:Java是否在缓存中存储变量值(在哪个缓存中?l1 l2还是l3)

我的另一个问题是可见性部分。例如:

public int num1 = 1;
public int num2 = 2;
public int num3 = 3;
public int num4 = 4;
public int num5 = 5;
...
num1 = 10;
num2 = 20;
num3 = 30;
num4 = 40;
num5 = 50;

在这个例子中,变量的执行顺序是不能保证的。如果我让Num2变得不稳定,它会保证Num1、Num2和Num3的执行顺序与它定义的完全一样,但是它不能保证Num4和Num5的执行顺序?

编辑我刚读完彼得·劳瑞的文章http://vanillajava.blogspot.com.es/2012/01/demonstrating-when-volatile-is-required.html他写道,“如果没有volatile,这会以多种可能的方式分解。一种方式是,两个线程各自认为自己已经更改了值,正在等待另一个,即每个线程都有自己的值缓存副本。”

所以我更困惑了。。关于这个

很抱歉问了这个可能很愚蠢的问题,但我真的很困惑。

共有3个答案

费星晖
2023-03-14

分配的顺序不受volatile的影响。关键字volatile保证多个线程访问相同的值,例如int值。这个变量的值永远不会被本地线程缓存:所有读写操作都将直接进入“主内存”。对变量的访问就好像它被封装在一个同步块中,并在自身上同步。

姬朗
2023-03-14

当您想要对这种行为进行准确描述时,了解Java语言规范总是很好的。在链接的章节中,您将找到有关线程行为和编译器重新排序的信息,以及volatile如何在这里发挥作用的信息。

陆子石
2023-03-14

包括JVM在内的大多数程序都没有显式地将变量放置在任何特定的缓存中

  • 是否完全消除了变量?
  • 它把它放在一个登记簿和哪一个?
  • 它是否将其放置在内存中的堆栈上?(以及相对于堆栈顶部的位置)
  • 它是否将它放置在堆中的对象中?(以及对象中的位置)

唯一的选择是变量是在对象中还是在堆栈上。(你也可以选择完全避免使用变量)注意,如果你把字段放在一个对象中,jit仍然只能把它放在堆栈中,如果它可以避免创建对象的话。

使num2volatile提供的唯一可见性保证是,如果你看到num2==20,你必须看到num1==10。您还可以保证在其他线程的某个点上看到num2==20。您可能会看到num3==3或num3==30。你可能永远不会在另一个线程中看到num3,因为它不是易变的或最终的。如果在第二次写入num2之前在另一个线程中读取该字段,可能会看到num3==0,这是未初始化的值。

每个值都有自己的缓存副本。

这不是由Java决定的,而是CPU的一个实现细节。每个核心在x64、Sparc和ARM中都有自己的L1和L2缓存。为了提高速度,这些缓存对每个内核都是本地的,这意味着它们可能彼此不同步。确保它们始终同步将大大降低它们的速度。

 类似资料:
  • 下面是 Java 里面的关键字。不能使用以下任一作为您的程序标识符。关键字 const 和 goto 语句被保留,即使他们目前尚未使用。true, false, 和 null 似乎是关键字,但它们实际上是字面值;你不能使用它们作为你的程序标识符。 abstract continue for new switch assert*** default goto*

  • 关键字是不能做为变量的。Lua 的关键字不多,就以下几个: and break do else elseif end false for function if in local nil not or repeat return then true until while

  • 模型 21.1 model 视图 21.1 view 处理器方法 21.1 handler method 处理器 21.1 handler 控制器 21.1 controller 命令对象 21.1 command object 表单返回对象 21.1 form-backing object 响应 21.1 response 视图解析器 21.1 view resolver 验证器 21.1.1

  • 智能合约使用的语言为golang定制版,屏蔽了部分golang关键字。 package、import: 谨慎使用,所有的import的模块都只能是链上的模块,不支持引用外部模块,会校验import的模块是否在链上。代码打包成交易时,会自动删除package和import,并将import按照规则转化为数组,最终的交易里是不允许包含这两个关键字的。 go/select: 由于该操作会出现并发,导致数

  • 关键字,C的关键字共有32个 数据类型关键字(12个) char,short,int,long,float,double,unsigned,signed,struct,union,enum,void 控制语句关键字(12个) if,else,switch,case,default,for,do,while,break,continue,goto,return 存储关键字(5个) auto,exte

  • 问题内容: 我目前正在尝试使我的java代码(使用eclipse)执行某些功能(如果说了某件事)。我正在使用Sphinx4库,这是我目前拥有的: 我想做的是在它说的那行: 如果我的发言是Hello Computer,Hello Jarvis,Good Morning Computer或Good Morning Jarvis,则运行该功能。或者换句话说,如果语音与.gram文件中的“ public

  • 问题内容: 我是Python的新手(通常在C#上工作),在最近的几天里开始使用它。 在一个类中,是否需要在对该类的数据成员和方法的调用之前添加前缀?因此,如果我要从该类中调用方法或从该类中获取值,则需要使用或,例如? 我只想检查一下,还没有我没有遇到过的较详细的方法。 问题答案: 没有比这更冗长的方法了。始终用于访问实例属性。请注意,与C ++不同,它不是关键字。您 可以 为方法的第一个参数指定所

  • C# 中的关键字是编译器预先定义好的一些单词,也可以称为保留字或者保留标识符,这些关键字对编译器有特殊的意义,不能用作标识符。但是,如果您非要使用的话也不是没有办法,只需要在关键字前面加上 前缀即可,例如 就是一个有效的标识符,而 则是一个关键字。 在 C# 中,有些关键字在代码的上下文中具有特殊的意义,例如 get 和 set,这样的关键字被称为上下文关键字(contextual keyword