【问题标题】:Count number of instances of a class in multi-threading environment?计算多线程环境中类的实例数?
【发布时间】:2016-11-14 21:11:51
【问题描述】:

我正在尝试计算在多线程环境下进程运行时生成的类实例的数量。我这样做的方法是通过查看这篇文章来增加构造函数中的静态计数器: How to Count Number of Instances of a Class

所以在多线程环境中,我是这样定义类的:

class Television {
      private static volatile int counter = 0;
      public Television(){
             counter ++;
      }
}

但是,我不确定上面的代码是否存在潜在的错误,因为我认为 java 中的构造函数并不意味着同步 并且counter++ 不是原子的因此,如果两个线程同时创建实例,代码是否是某种错误?但我还不太确定。

【问题讨论】:

  • 正确,有一个错误,因为计数器的读取和写入计数器不是原子执行的。使用AtomicInteger
  • 使用原子计数器。教程/基本/并发/atomicvars.html
  • 当然还有;一个有趣的问题是:你为什么要这样做?通过了解实例数,您打算解决什么样的问题?
  • @GhostCat 很好,它偶尔有用(非常偶尔);我的问题是为什么让它成为Television 的静态属性,而不是TelevisionFactory 的实例变量。可变的全局状态是纯粹的邪恶。
  • @AndyTurner 非常感谢,这很有趣。您能解释一下如何使用 TelevisionFactory 进行计数吗?

标签: java multithreading


【解决方案1】:

此代码中有一个错误(特别是竞争条件),因为读取计数器和写入计数器不是原子执行的。

换句话说,两个线程可以读取counter 的相同值,递增该值,然后将相同的值写回变量。

Thread 1    Thread 2
========    ========

Read 0
            Read 0
Increment
            Increment
Write 1
            Write 1

所以之后的值将是 1,而不是 2。

请改用AtomicIntegerAtomicInteger.incrementAndGet()

【讨论】:

    【解决方案2】:

    由于counter++ 不是原子的,您可以将其替换为JDK 的AtomicInteger,它是线程安全的。

    你可以AtomicInteger的使用getAndIncrement()方法如下图:

    class Television {
          private static final AtomicInteger counter = new AtomicInteger();
          public Television(){
                counter.getAndIncrement();
          }
    }
    

    AtomicInteger 用于原子化等应用程序中 递增的计数器,并且不能用作替代 整数。

    你可以看here

    【讨论】:

    • 无需将 AtomicInteger 标记为 volatile。在底层,它使用 volatile 变量来存储值。
    【解决方案3】:

    这里有两种方法可以绕过底层的“++ on int”不是原子操作:

    A)按照其他人的建议,使用AtomicInteger

    B) 引入一个所有 ctor 都可以用来同步的通用 LOCK;喜欢:

    private final static Object LOCK = new Object();
    
    public Television() {
      synchronized (LOCK) { 
        counter++; 
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-29
      • 1970-01-01
      相关资源
      最近更新 更多