当前位置: 首页 > 知识库问答 >
问题:

我可以消除嵌套在同步方法中的私有字段上的同步吗?

顾俊哲
2023-03-14

我有这个遗留的伪代码:

public class Wrapper {
  private volatile Sink sink;

  public synchronized void flushSink() {
    if (sink != null) {
      synchronized (sink) {
        sink.flush();
      }
    }
  }

  public void close()  throws IOException {
    var sink = this.sink;
    if (sink != null) {
      sink.receivedLast();
    }
  }
}

我的问题是关于嵌套同步块。

据我了解,在这种情况下提到的块是多余的,就好像两个线程同时调用 flushSink(),那么一次只有一个线程可以访问私有字段接收器。因此,代码可以简化为

public class Wrapper {
  private volatile Sink sink;

  public synchronized void flushSink() {
    if (sink != null) {
      sink.flush();
    }
  }
}

有可能进一步消除racy读取到

public class Wrapper {
  private volatile Sink sink;

  public synchronized void flushSink() {
    var sink = this.sink;
    if (sink != null) {
      sink.flush();
    }
  }
}

所以我的问题是,这种重构在同步和JMM方面是否正确,如果正确(或者不正确)-是否有基于JCStress的测试证明了这一点?

共有1个答案

姬温文
2023-03-14

据我所知,在这种情况下,提到的块是多余的,就像两个线程同时调用flushSink(),那么一次只有其中一个可以访问私有字段接收器。因此,代码可以简化为

只要代码中没有其他地方可以在同步块中访问< code>sink,它就是多余的。

例如,如果将< code>close()方法更改为以下内容,

public void close()  throws IOException {
  var sink = this.sink;
  if (sink != null) {
    synchronized(sink) {
      sink.receivedLast();
    }
  }
}

那么flushSink() 中的同步块不会是无用的,因为它可以确保 receivedLast() 和 flush() 不会同时被调用。

 类似资料:
  • 问题内容: 我正在查看包含同步方法的第三方库中的一些代码,在此方法中,有一个锁定在实例变量上的同步块。与此类似: 这有意义吗?如果是这样,在同步方法中使用同步语句有什么好处? 鉴于同步方法锁定了整个对象,对我来说似乎是多余的。在使用非私有的实例变量时,这种方法是否有意义? 问题答案: 在您的示例中,该方法 同时 锁定了和的实例。其他方法可能仅锁定对象的实例 或 对象。 因此,是的,这完全取决于他们

  • 问题内容: 我在Heinz Kabutz的 Java专家 通讯版本中看到了这一点,尽管Kabutz博士的文章的其余部分(乃至全部)都得到了很好的解释和详细说明,但他似乎掩盖了这段代码的作用,或更重要的是,它的意义是: 嵌套块的含义是什么?这如何影响尝试执行的不同线程? 问题答案: 有两个可能需要注意的问题 如果使用等待/通知,嵌套锁很容易导致死锁。这是为什么的解释。http://tutorials

  • 所以我写了这个服务器脚本,它应该接收一个用户名,然后继续其他一些代码。但是我收到了这个错误: "OSError:[WinError 10057]不允许发送或接收数据的请求,因为套接字未连接,并且(当使用sendto调用在数据报套接字上发送时)未提供地址" 我的理论是服务器和客户端没有同步,所以服务器认为它没有收到消息。如何改进我的代码,以便服务器实际接收消息?(我试过尝试块) 我的代码: sock

  • 请看下面给我带来麻烦的方法: 然后是run方法:

  • 我正在处理来自TCP套接字的大量事件(每秒10个套接字),因此我使用多线程来处理这些事件。 大多数情况下,这是正确的,但有时会出现这些事件的雪崩,有时我会得到一个ConcurrentModificationException: 12-10 14:08:42.071:E/AndreidRuntime(28135):致命例外:线程-369 12-10 14:08:42.071:E/AndreidRun

  • 是否可以调用一个异步方法,以便它从一个同步的方法异步运行?我不关心它挂起同步调用程序直到它返回,而是希望该方法被异步调用。