【问题标题】:Do accesses in a constructor to a shared static variable need to be synchronized?构造函数中对共享静态变量的访问是否需要同步?
【发布时间】:2012-03-01 19:56:22
【问题描述】:

我知道构造函数不能在 Java 中同步。这是否意味着如果构造函数修改了类中的静态变量,并且可以从多个线程调用构造函数,则需要同步访问,如图所示?

public class MyClass {
  private static int count = 0;

  public MyClass() {
    synchronized(MyClass.class) {
      count++;
    }
    ...
  }
}

【问题讨论】:

  • 您确实意识到静态、可变变量是一种代码味道,对吧?
  • @LouisWasserman,我没有意识到它们被认为是一种气味,但我现在知道了。谢谢。
  • Here 是一个可以解释为什么它们是代码味道的引文。它侧重于单例——这是静态的一个特殊例子——但这些问题更普遍。

标签: java multithreading constructor synchronization static-members


【解决方案1】:

绝对 - 毕竟,它正在访问共享资源,可能通过许多线程。我个人会改用AtomicInteger

public class MyClass {
  private static final AtomicInteger count = new AtomicInteger();

  public MyClass() {
    count.incrementAndGet();
  }
}

请注意,我们现在可以将变量设为 final,因为 变量 不会改变值,并且我们不需要再同步,因为 java.util.concurrent.atomic 中的类的全部点是它们可以在没有额外同步的情况下以原子方式使用。

即使您处于需要同步的情况,我也不会使用MyClass.class 来执行此操作 - 这是其他代码可能决定同步的参考,因此您可以' ' 真的不再推理你的代码了。我会写(同样,仅当 AtomicInteger 出于某种原因还不够好时):

public class MyClass {
  private static final Object countLock = new Object();
  private static int count = 0;

  public MyClass() {
    synchronized(countLock) {
      count++;
    }
    ...
  }
}

(在这种情况下,您还希望在您访问 count 的其他任何地方同步 countLock,即使只是为了阅读。)

【讨论】:

  • 大概count 正在维护以供其他地方使用。在第二个示例中,您还希望在 countLock 上同步对 count 的任何读取访问。
  • @TedHopp 在这种情况下,最好让 count volatile 并避免在读取情况下同步(当然,仍然在增量情况下同步)。
  • @increment1 - 将其声明为 volatile 仍允许在更新过程中读取该变量。这不会弄乱更新(非同步更新的方式),但意味着返回的值将由竞争条件决定。
  • @TedHopp 在额外的外部同步之外,访问此类的两个独立线程已经受到竞争条件的影响(更新是在另一个线程读取之前还是之后发生)。简单地同步读取计数并不能解决竞争条件会影响此代码的情况,因此我认为 volatile 在这种情况下同样具有确定性。如果有一个例子表明这是不真实的,那么我有兴趣看到它,因为我想不出一个。
  • @espertus:如果您在访问变量时始终在countLock 上同步,则不会。一次只有一个线程会在这样的同步块中,并且内存模型确保写入永远不会移动到块结束“之后”,读取永远不会移动到块开始“之前”跨度>
【解决方案2】:

某种同步是必要的,这会奏效,是的。它将完成与同步静态方法相同的事情。您可以考虑改用AtomicInteger

【讨论】:

    【解决方案3】:

    对于这种情况,我建议使用AtomicInteger

    【讨论】:

    • 我觉得有必要创造一个词:“被Skeeted!”
    • @Gray - 确实如此。但是,必须在应得的地方给予信任。这是一个很好的答案。
    • 当然可以。这就是为什么他是约翰·斯基特。
    • @Gray - 好吧,我会颠倒因果,但我同意。 :)
    猜你喜欢
    • 2016-06-23
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-25
    • 1970-01-01
    相关资源
    最近更新 更多