Kotlin/Java - 多线程 - 例如,当消费者流被另一个线程替换时会发生什么情况

问题描述 投票:0回答:1

我有一个类,它有另一个类的内部实例。

@Singleton
class ClassA {

    private var classBInstance: ClassB

    init{
        classBInstance = ClassB()
    }

    fun performOperation(): Result {
        return classBInsatnce.doSomething()
        // doSomething() takes about 4 seconds
     }

     fun updateClassB() {
       classBInstance = ClassB()

     }
}

ClassA 是一个单例,由多个线程使用,并在其上调用performOperation()。 现在,如果消费者调用performOperation,从而在内部调用classBInstance.doSomething(),并且在处理过程中(持续4秒),如果其他人调用updateClassB(),则变量classBInstance现在持有一个新实例,如果B 类。那么前面的消费者会发生什么,他的操作 (doSomething() 仍在 ClassB 的前一个实例中进行。

  • doSomething() 是否仍会使用 ClassB 的早期实例来执行其完整操作?对于这个消费者来说。对于任何进一步的请求,将使用 ClassB 的新实例的 doSomething。
  • 或者一旦变量被替换,前一个 ClassB 实例的 doSomething() 中是否会出现一些问题。

我问,因为我的想法是,我想确保当 classBInstance 持有的实例更新为新实例时,performOperation() 处理的任何现有调用都是使用 ClassB 的旧实例完成的,并且仅在 ClassB 新实例之后完成被设置到 classBInstance 变量中,那么只有新的实例 classB 用于对 PerformOperation() 的任何进一步调用

有人可以帮忙澄清一下吗? 谢谢

我尝试阅读有关类实例及其操作方式的信息,但对这种边缘情况感到困惑

java multithreading kotlin instance-variables multiple-instances
1个回答
0
投票

在大多数情况下,Java 内存模型 应该适用于此。

首先,我假设您的单例是以线程安全的方式创建的(例如,它是一个

val
)。

我发现您的代码存在两个问题:

  • 第一期是
    ClassB
    的“不安全出版”。当您执行
    classBInstance = ClassB()
    时,可能会发生指令重新排序并且分配发生在
    ClassB
    完全初始化之前。
  • 第二个问题是可见性。如果一个线程设置了
    classBInstance
    ,由于 CPU 缓存的原因,它可能对其他线程不可见。您需要确保
    classBInstance
    已更新。

您可以通过用

@Volatile
标记 classBInstance 来解决这两个问题。这确保了可见性,并在访问之间建立了发生之前的关系。当一个线程设置
classBInstance
时,此操作将在进一步读取变量之前发生,并且 JVM 将确保后续读取(由其他线程)读取更新的值。

© www.soinside.com 2019 - 2024. All rights reserved.