Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/tensorflow/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在多线程环境中,是否必须为长类型实例常量声明volatile?_Java_Multithreading_Volatile - Fatal编程技术网

Java 在多线程环境中,是否必须为长类型实例常量声明volatile?

Java 在多线程环境中,是否必须为长类型实例常量声明volatile?,java,multithreading,volatile,Java,Multithreading,Volatile,我有一个多线程的Java程序,在多线程调用的函数中读取的长类型常量很少。这些读/赋值操作在同步的块之外,这些常量与被调用的/同步的块在同一类中声明 建议将这些长常量设置为易变的吗?一旦初始化,这些常量就不会被更改。我没有看到任何不正确的程序行为,只是想澄清一下 这是伪代码 public class ThreadSafeClass { private long long_val = 100; public int calculate(){ long local_long=long_val;

我有一个多线程的Java程序,在多线程调用的函数中读取的长类型常量很少。这些读/赋值操作在
同步的
块之外,这些常量与被调用的/
同步的
块在同一类中声明

建议将这些长常量设置为易变的吗?一旦初始化,这些常量就不会被更改。我没有看到任何不正确的程序行为,只是想澄清一下

这是伪代码

public class ThreadSafeClass {
private long long_val = 100;

public int calculate(){

long local_long=long_val;

synchronized(this){
  //use local_long
}}}

如果某事物是常量,则其值不能更改

我看到的
volatile
关键字基本上是缓存策略。这将确保如果变量的值发生更改,那么该更改将反映在访问该变量的所有线程上

但由于常量永远不会更改,所以这也没有任何用处,因为您不能由于缓存而遇到挂起或任何情况。由于常量通常标记为
final
,因此不需要这样做

下面是我所说的一个挂起的例子:

static boolean done = false;
public boolean isDone() 
{
    return done;
}
在另一个线程上

// do something, wait until this other thing is done...

while (! isDone()) 
{
    // Even if the thing becomes done, this is infinite: the value has been cached.
}

// when something else is done, then do the next thing.


另外,如果常量已经是
final
,那么将其标记为
volatile
也会导致编译错误。干杯:)

如果
常量被声明为
最终
,并且它们被安全地发布了1,那么它们就不需要声明为
易失性
。JLS中规定了
final
字段的特殊属性


如果
long
常量不是
final
,则需要进行更深入的分析,以确定它们是否真的是常量,以及初始化的结果是否对所有线程都可见

将(非
final
)常量声明为
volatile
可以实现这一点,但这不是一种好的(有效的)方法。深入分析(即仔细分析关系发生之前的情况)可能会发现,
volatile
是不必要的。例如,如果一个线程初始化了常量,然后在使用它们的所有其他线程上调用了
start()
,那么(我认为)您可以不进行
volatile
和其他同步

但是。。。将常量声明为
final
是更稳健的方法2


请在更新的问题中重新输入伪代码:


  • 伪代码版本是不正确的,即使假定它在其他地方没有更改。问题在于是否保证所有线程都能看到初始值。问题在于,内存模型不需要创建
    ThreadSafeClass
    实例的线程刷新
    long_val
    。这意味着另一个线程在调用
    calculate()
    时可以看到默认的初始值(零)

  • 如果
    local_long
    synchronized
    块内初始化,则伪代码是正确的

  • 如果
    long\u val
    final
    volatile,则不需要
    synchronized`块(至少为此目的)。(出于不同的原因……)


  • 1-基本上,您需要确保在“final”生效之前没有其他线程使用常量字段。对于最终实例字段,这意味着在构造函数返回之前。对于最后一个静态字段,这意味着在类初始化完成之前。。。当然要注意的是,作为编译时常量的静态final字段的处理方式不同


    2-我排除了使用反射更改
    最终
    字段的边缘情况。这是邪恶的,它使所有关于可见性的保证失效。不要这样做。

    好的,这个程序是由其他开发人员编写的,我看不到任何地方的值被更改,所以我称它为常量,但它没有标记为final。如果它的行为方式是这样的,那么它可能应该被标记为final。@Sabir_Khan好吧,如果它不被改变,volatile关键字就没有什么用处了。我将提供一个我在回答中提到的挂起的代码示例。这里是一个长实例变量,初始化为固定值,在代码中任何地方都不会更改(代码由其他人编写),未标记为final的正在函数局部变量中读取,并且该局部变量正在该函数内的同步块中使用。我认为Long的原子读取问题不应该是这个场景的问题。@Sabir_Khan只是想了解一些背景,程序是多线程的吗?如果不是,你真的不需要担心同步或者类似的疯狂事情。我不是说原子读取问题。我说的是一个更普遍的问题,阅读线程是否看到正确的初始值。。。当初始值由另一个线程设置时。所有基元类型都会出现同样的问题。感谢您的帮助,我根据我的回忆在问题中添加了psuedo代码,因为实际代码在office PC上,而我目前无法访问该代码。最初的开发人员可能有其他一些意图,但我记得没有看到任何地方更改了
    long\u val
    。伪代码版本不正确,但如果
    local\u long
    是在
    synchronized
    块中初始化的,则是正确的。不存在易失性常数,但是这里也没有long类型的常量变量。有整数常量和非常量长变量。这里您缺少的是'final',它将使长变量保持不变,从而消除您的问题。请定义“constant”的含义(在您的程序上下文中)。如何定义常数?如果未使用
    final
    keywor