Java 在多线程环境中,是否必须为长类型实例常量声明volatile?
我有一个多线程的Java程序,在多线程调用的函数中读取的长类型常量很少。这些读/赋值操作在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;
同步的
块之外,这些常量与被调用的/同步的
块在同一类中声明
建议将这些长常量设置为易变的吗?一旦初始化,这些常量就不会被更改。我没有看到任何不正确的程序行为,只是想澄清一下
这是伪代码
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