【问题标题】:Can two threads access same method at once after access of synchronized property?访问同步属性后,两个线程可以同时访问同一个方法吗?
【发布时间】:2021-09-20 16:00:13
【问题描述】:

我对我的代码中的某些情况有点困惑。

private var state by synchronized<PlayerState>(Stopped())

val asStarted get() = state as? Started
val asStopped get() = state as? Stopped

inner class Stopped : PlayerState {
    fun start(bpm: BPM = BPM(), volume: Int? = null) {
        state = Started(bpm, volume)
    }
}

假设两个线程正在尝试执行player.asStopped?.start(),我这里有问题吗?我需要输入这样的内容吗?

inner class Stopped : PlayerState {
    @Synchronized
    fun start(bpm: BPM = BPM(), volume: Int? = null) {
        if(state is Started) return
        state = Started(bpm, volume)
    }
}

感谢您的帮助。

【问题讨论】:

  • 多线程代码即使是聪明人也很难做到正确。我认为没有所有自定义锁定的事件线程和协程将是一个更安全的想法。
  • @duffymo 我不知道你对热协程的实现有什么了解,但对我来说它似乎是相当高级的库。我正在编写性能关键的 midi 音序器应用程序,这些应用程序必须在最大限度地使用 android 的 cpu 时非常顺利地运行,在我看来,这部分代码中的任何高级抽象都是毫无疑问的。

标签: java multithreading kotlin thread-safety


【解决方案1】:

你的担心是对的。

您的代码的第一个版本确实存在竞争条件,因为两个线程都可以创建 Started 对象,然后设置它们。一次只能有一个线程执行 setter,但第二个线程可以在第一个线程离开后立即进入。

这可能不是问题。 (synchronized 委托仍将防止访问 state 时出现任何低级问题,例如查看部分构造的值。 而且看起来没有其他状态需要与您的 state 属性相关联,所以它不能进入​​不一致的状态。) 但是能够启动两次可能并不好!

我不认为您的代码的第二个版本存在任何线程问题,如所写。 (如果它没有@Synchronized,那么它确实会有time-of-check-to-time-of-use 竞争条件。)

但是,有点令人困惑,因为它使用了两种独立的锁定机制@Synchronized 方法锁定 Stopped 对象,而 by synchronized 状态有自己的锁定),以及即使在这个非常简单的示例中,也很难遵循这些锁的交互方式。

我还怀疑它可能会导致周围代码出现竞争条件。一旦开始,您的播放器可以再次停止吗?如果是这样,stop() 方法将锁定什么 - 如果是 Started 对象,那么这是另一个锁定,我可以在那里看到一些竞争条件。

因此,我强烈建议将其重构为仅使用单个锁。

我不知道您的代码正在使用的 synchronized 委托。如果它具有某种测试和设置、比较和交换或类似功能,那么您可以使用它来做您需要的事情。否则,恐怕最好放弃委托并自己进行锁定。

这确实引发了关于设计的更广泛的问题:为什么你的 Stopped 类有 start() 方法? 肯定是 player 开始的并停止,状态只是它的反映吗?所以改变状态根本不是对当前状态的操作

解决该设计问题几乎肯定会更容易修复锁定。

【讨论】:

  • 有一个细节我只使用了两个线程 .. UI 和 worker 所以。所以没有更多的工作线程只有一个.. 好的,谢谢,如果我们谈论设计,我永远不会完成我的应用程序,设计是在进行中的工作和过程中的演变.. 代码库非常庞大,没有时间进行任何讨论只需要确定现在关于这个,非常感谢..我实际上还没有任何死锁,我最终得到了第二版代码,但肯定有我没有看到的问题,也许我将来会用不同的方法重写它。
  • 我不会按照你的“为什么你的 Stopped 类有一个 start() 方法??”讨论即使你我的自我肯定也想哈哈,我脑子里有很多意见,谢谢
猜你喜欢
  • 1970-01-01
  • 2013-10-20
  • 2019-02-07
  • 1970-01-01
  • 1970-01-01
  • 2015-07-06
  • 2014-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多