代码之家  ›  专栏  ›  技术社区  ›  biasedbit

原子布尔与同步块

  •  6
  • biasedbit  · 技术社区  · 15 年前

    synchronized 带有 AtomicBoolean .

    :

    public void toggleCondition() {
        synchronized (this.mutex) {
            if (this.toggled) {
                return;
            }
    
            this.toggled = true;
            // do other stuff
        }
    }
    

    另一种选择是 :

    public void toggleCondition() {
        if (!this.condition.getAndSet(true)) {
            // do other stuff
        }
    }
    

    利用 原子布尔 的CAS属性应该比依赖同步快得多,所以我运行了一个 little micro-benchmark

    对于10个并发线程和1000000次迭代, 原子布尔 阻止。

    使用AtomicBoolean在toggleCondition()上花费的平均时间(每个线程):0.0338

    同步时在toggleCondition()上花费的平均时间(每个线程):0.0357

    我知道微观基准值的是它们的价值,但它们之间的差异不应该更大吗?

    2 回复  |  直到 15 年前
        1
  •  6
  •   Stephen C    15 年前

    我知道微观基准值的是它们的价值,但它们之间的差异不应该更大吗?

    更改您的基准测试,以便每个线程将条件切换几百万次。这将保证大量的锁争用,而且我希望您会看到性能上的差异。

    如果您打算测试的场景只涉及每个线程一个切换(和10个线程),那么您的应用程序不太可能遇到争用,因此使用AtomicBoolean也不太可能有任何不同。

    在这一点上,我应该问你为什么要把注意力集中在这一方面。您是否分析了您的应用程序并确定 真正地

        2
  •  3
  •   user177800 user177800    15 年前

    从实际的实现来看,我的意思是看代码比一些微基准(在Java或任何其他GC运行时都没有用)要好得多,我并不惊讶它“明显更快”。它基本上是做一个隐式同步部分。

    /**
     * Atomically sets to the given value and returns the previous value.
     *
     * @param newValue the new value
     * @return the previous value
     */
    public final boolean getAndSet(boolean newValue) {
        for (;;) {
            boolean current = get();
            if (compareAndSet(current, newValue))
                return current;
        }
    }
    
    /**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return true if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(boolean expect, boolean update) {
        int e = expect ? 1 : 0;
        int u = update ? 1 : 0;
        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
    }
    

    com.sun.Unsafe.java

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapInt(Object o, long offset,
                                                  int expected,
                                                  int x);
    

    这里面没有魔法,资源争夺是一个婊子,非常复杂。这就是为什么使用 final 变量和处理不可变数据在像Erlang这样的实际并发语言中非常普遍。所有这些占用CPU时间的复杂性都被忽略了,或者至少转移到了不太复杂的地方。

    推荐文章