【问题标题】:Thread Safety: Maximum efficiency线程安全:最高效率
【发布时间】:2022-01-30 20:36:11
【问题描述】:

晚上好,

我正在尝试了解我如何使用多线程以及如何在上下文中实现线程安全。

当我想达到线程的最大速度时,我会使用:

    public void addMarketOrder(MarketOrder marketOrder) {
    if (marketOrder.id != this.id) {
        return;
    }
    synchronized (this) {
        ordered += marketOrder.ordered;
    }
}

或者只是同步整个方法?

    public synchronized void addMarketOrder(MarketOrder marketOrder) {
    if (marketOrder.id != this.id) {
        return;
    }
    ordered += marketOrder.ordered;
}

【问题讨论】:

    标签: java multithreading thread-safety


    【解决方案1】:

    假设ids 不变,第一种情况优于第二种情况。如果ids 不匹配,第一种情况会避免同步。第二种情况即使没有任何写操作也会同步。

    【讨论】:

      【解决方案2】:

      如果你想要一个高效的多线程系统,那么就不要让线程相互通信。如果线程争用相同的数据,即使您使用 volatile 或 Atomics 等快速替代方案,速度也会显着降低。

      我不确定您的代码的哪些部分需要是线程安全的。如果只是原子增加计数器的问题,那么将“有序”字段设置为 AtomicLong 并调用 getAndAdd 将是一个不使用任何锁的相当快的解决方案。

      【讨论】:

        【解决方案3】:

        您暗示的是双重检查锁定。正确的形式是:

            public void addMarketOrder(MarketOrder marketOrder) {
            if (marketOrder.id != this.id) {
                return;
            }
            synchronized (this) {
                if (marketOrder.id != this.id) {
                   ordered += marketOrder.ordered;
                }
            }
        }
        

        因为你不应该假设因为条件变为真,它就会继续为真。

        此外,如果您在没有同步的情况下读取 id,它应该是易失性的,因为编译器可能会在某些情况下优化内存读取,并且一个线程中保存的值可能与另一个线程不同。此外,当非易失性时,编译器可以更改为操作顺序,假设单个线程可能会使您的代码在使用多个线程运行时行为异常。

        波动性规则多线程同步块之外访问的任何变量都必须是final易失性。否则在某些情况下您会遇到线程可见性问题。

        您也可以毫无问题地同步整个方法。但是同步整个方法会降低效率(如果你有很多处理器,这可能很重要,这是一个竞争激烈的方法)。

        【讨论】:

        • volatile 变量规则略有不同。如果读取 volatile 变量,看到对该变量的 volatile 写入,则在该写入和读取之间存在发生前边缘。我不确定“在缓存中屏蔽”是什么意思。现代 CPU 上的缓存始终是连贯的,因此不依赖于可变的变量。
        • 嗯..也许缓存不是表达这一点的正确方式。但是可能发生的情况是您的变量位于一个内核中的寄存器上,并且该值在 Ram 中被修改。因为您的编译器已经优化了“不必要的内存读取”,所以您的寄存器(或堆栈)中的值不再正确。
        • @pveentjer 我试图修复它以使其更清晰。查看新的编辑。
        • @pveentjer 您指的是关于“发生在之前”的排序,我称之为操作顺序规则,它与可见性不完全相同,但它是相关的。
        • 发生在暗示可见性之前。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-20
        • 1970-01-01
        相关资源
        最近更新 更多