【问题标题】:Necessity of synchronized on local variable局部变量同步的必要性
【发布时间】:2013-08-19 16:02:22
【问题描述】:

在 JSON-java 库 (org.json.JSONArray) 中,我发现此代码 sn-p 带有一个围绕方法局部变量的 synchronized

public String toString(int indentFactor) throws JSONException {
    StringWriter sw = new StringWriter();
    synchronized (sw.getBuffer()) {
        return this.write(sw, indentFactor, 0).toString();
    }
}

我不明白这里同步的必要性,因为StringWriter 仅对给定方法是本地的(以及为什么同步在缓冲区上)。这里真的需要同步吗?如果,为什么?

【问题讨论】:

  • 没有必要。使用默认构造函数,缓冲区是一个新实例化的对象。 buf = new StringBuffer(); 在构造函数中。
  • 请注意,org.json 库的作者是 JavaScript 程序员,而不是 Java 程序员,这一事实在整个代码中都有体现。对于严重的 JSON 处理,请考虑使用 Google 的 Gson 库。

标签: java synchronized


【解决方案1】:

这可能是性能优化。在 oracle jvm 中,重新获取已经持有的锁非常快。据推测,write 调用正在对 StringBuffer 进行多次调用。通过在调用 write 之前锁定,锁定将在所有这些调用中保持,而不是在每次调用时释放并重新获取。

【讨论】:

  • 从 Java 6 开始,锁偏向意味着无论如何获取非竞争锁都很快。
  • @ChrisJester-Young - 是的,我不知道特定的性能优化仍然(或曾经)有多相关。
  • 我不会低估每次通话都会被释放和重新获得write() 调用根本不会尝试和 synchronizeWriter 上。在 OP 的问题中的 toString(int) 方法中,锁只被获取和释放一次。
  • @SotiriosDelimanolis - StringBuffer 的所有方法(StringWriter 的基础)都是同步的。
  • @jtahlborn 非常有趣,+1。
【解决方案2】:

StringWriter 的空构造函数是

/**
 * Create a new string writer using the default initial string-buffer
 * size.
 */
public StringWriter() {
    buf = new StringBuffer();
    lock = buf;
}

没有任何东西是共享的,因此synchronized 块是不必要的。

除非...write 委托给另一个线程,但我对此表示严重怀疑。

【讨论】:

    【解决方案3】:

    getBuffer() 返回一个StringBuffer,根据文档,StringBuffer 已经同步:

    字符串缓冲区可以安全地被多个线程使用。这些方法在必要时进行同步,以便任何特定实例上的所有操作都表现得好像它们以某种串行顺序发生,该顺序与所涉及的每个单独线程进行的方法调用的顺序一致。

    这意味着在StringBuffer 上再次同步完全是多余的。对StringWriter 的更改将自动同步,因为它在内部使用同步的StringBuffer

    由于StringWriter实例是方法调用的本地实例,不可能有多个线程同时访问同一个实例,这也使得同步变得不必要。

    【讨论】:

      【解决方案4】:

      这是一个错误。 每个线程在方法中创建自己的局部变量并在其上进行同步。每次进入方法线程都会创建自己的对象监视器,因为它是本地的并且只存在于线程的堆栈中,因此不能被另一个线程持有!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-16
        • 2023-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-17
        • 1970-01-01
        • 2020-11-27
        相关资源
        最近更新 更多