Multithreading 演员';s值有时返回null
我有一个演员和一些其他对象:Multithreading 演员';s值有时返回null,multithreading,scala,akka,future,Multithreading,Scala,Akka,Future,我有一个演员和一些其他对象: object Config { val readValueFromConfig() = { //....} } class MyActor extends Actor { val confValue = Config.readValueFromConfig() val initValue = Future { val a = confValue // sometimes it's null val a = Config.readValueF
object Config {
val readValueFromConfig() = { //....}
}
class MyActor extends Actor {
val confValue = Config.readValueFromConfig()
val initValue = Future {
val a = confValue // sometimes it's null
val a = Config.readValueFromConfig() //always works well
}
//..........
}
上面的代码是我实际拥有的非常简化的版本。奇怪的是,有时val a=confValue
返回null
,而如果我用val a=Config.readValueFromConfig()
替换它,那么它总是工作得很好
我想知道,这是因为与演员互动的唯一方式是向其发送信息吗?因此,由于val confValue
不是局部变量,我必须使用val a=Config.readValueFromConfig()
(不同的对象,而不是参与者)或val a=self!获取配置值
,然后读取结果
我想知道,这是因为与演员互动的唯一方式是向其发送信息吗?因此,由于val confValue不是局部变量,我必须使用val a=Config.readValueFromConfig()(另一个对象,而不是参与者)
仅仅因为它不是演员,并不意味着它一定是安全的。可能不是
或者val a=self!获取配置值,然后读取结果
几乎是这样。你是说self?GetConfigValue,我认为-这将返回一个未来
,然后您可以映射它<代码>代码>不返回任何内容
您不能直接在Future
中读取参与者的变量,因为(通常)Future
可以在任何线程、任何处理器内核上运行,并且您没有任何内存障碍来强制CPU缓存从主内存重新加载值
val readValueFromConfig() = { //....}
我想知道,这是因为与演员互动的唯一方式是向其发送信息吗?因此,由于val confValue不是局部变量,我必须使用val a=Config.readValueFromConfig()(另一个对象,而不是参与者)
仅仅因为它不是演员,并不意味着它一定是安全的。可能不是
或者val a=self!获取配置值,然后读取结果
几乎是这样。你是说self?GetConfigValue,我认为-这将返回一个未来
,然后您可以映射它<代码>代码>不返回任何内容
您不能直接在Future
中读取参与者的变量,因为(通常)Future
可以在任何线程、任何处理器内核上运行,并且您没有任何内存障碍来强制CPU缓存从主内存重新加载值
val readValueFromConfig() = { //....}
这给了我一个编译错误。我猜你的意思是没有括号
val readValueFromConfig = { //....}
相同的逻辑和不同的计时给出不同的结果=竞争条件
val confValue=Config.readValueFromConfig()
总是在构建MyActor
对象的过程中执行(因为它是MyActor的一个字段)。有时它返回null
val a=Config.readValueFromConfig()//始终运行良好
始终在以后执行-在构建MyActor之后,当它的执行器执行未来的initValue
时。这似乎永远不会返回null
可能的原因:
如果readValueFromConfig
的主体依赖于另一个主体,则可以对此进行解释
并行/异步操作已完成。您是否有可能异步读取配置?给定此方法的名称,它可能只是从文件中同步读取-这意味着这不是原因
单例对象不是线程安全的??我编译了你的代码。以下是单例对象java类的反编译:
public final class Config
{
public static String readValueFromConfig()
{
return Config..MODULE$.readValueFromConfig();
}
}
public final class Config$
{
public static final MODULE$;
private final String readValueFromConfig;
static
{
new ();
}
public String readValueFromConfig()
{
return this.readValueFromConfig;
}
private Config$()
{
MODULE$ = this;
this.readValueFromConfig = // ... your logic here;
}
}
嗯。。。除非我弄错了,否则这是不安全的
如果两个线程正在访问readValueFromConfig
(假设Thread1首先访问它),那么在方法private Config$()
中,MODULE$
在this.readValueFromConfig
设置之前不安全地发布(引用this
会过早地转义构造函数)。在设置之前,位于后面的Thread2可以读取模块$.readValueFromConfig
。如果“”,很可能会出现问题。。。这里的逻辑很慢,阻塞了线程,这正是同步I/O所做的
故事的寓意:避免参与者(或者任何线程,包括执行者)使用有状态的单例对象,或者通过非常谨慎的编码风格使它们成为线程安全的。解决方法:更改为def
,它在内部将值缓存在私有val
中
这给了我一个编译错误。我猜你的意思是没有括号
val readValueFromConfig = { //....}
相同的逻辑和不同的计时给出不同的结果=竞争条件
val confValue=Config.readValueFromConfig()
总是在构建MyActor
对象的过程中执行(因为它是MyActor的一个字段)。有时它返回null
val a=Config.readValueFromConfig()//始终运行良好
始终在以后执行-在构建MyActor之后,当它的执行器执行未来的initValue
时。这似乎永远不会返回null
可能的原因:
如果readValueFromConfig
的主体依赖于另一个主体,则可以对此进行解释
并行/异步操作已完成。您是否有可能异步读取配置?给定此方法的名称,它可能只是从文件中同步读取-这意味着这不是原因
单例对象不是线程安全的??我编译了你的代码。以下是单例对象java类的反编译:
public final class Config
{
public static String readValueFromConfig()
{
return Config..MODULE$.readValueFromConfig();
}
}
public final class Config$
{
public static final MODULE$;
private final String readValueFromConfig;
static
{
new ();
}
public String readValueFromConfig()
{
return this.readValueFromConfig;
}
private Config$()
{
MODULE$ = this;
this.readValueFromConfig = // ... your logic here;
}
}
嗯。。。除非我弄错了,否则这是不安全的
如果两个线程正在访问readValueFromConfig
(假设Thread1首先访问它),那么在方法private Config$()
中,MODULE$
将被取消