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$
    将被取消