如何在Java中实现对象计数器 [英] How to implement object counter in Java

查看:401
本文介绍了如何在Java中实现对象计数器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一位采访者问我


如何实现一个Foo类,你可以在哪里计算该类的
个实例。有更多的线程正在创建该类Foo的
实例。

How can you implement a class Foo, where you will be able to count instances of that class. There are more threads which are creating instance of that class Foo.

我用以下代码回复了

public class Foo {
    private static int count = 0;

    public Foo() {
    incrementCount();
    }

    public void incrementCount() {
        synchronize (Foo.class) {
            count++;
        }
    }
} 

她又问了一遍我


如果线程结束,计数器应该减少,你怎么能这样做?

If a thread ends, counter should be decrement, how can you do that?

我没有回答这个问题。

我知道敲定()方法,但它取决于垃圾收集器,即使我们覆盖 finalize,也会调用此方法)

I know about finalize() method, but it depends on Garbage collector that when this method will be called, even if we override finalize().

我还没有解决方案,你能解释一下吗?

I have no solution yet, can you explain it please?

推荐答案

你可以将Thread的 Runnable 包装在另一个<$ c $中c> Runnable 会减少计数器:

You could wrap the Thread's Runnable inside another Runnable that would decrement the counter:

Thread createThread(final Runnable r) {
  return new Thread(new Runnable() {
    @Override public void run() {
      try {
        r.run();
      } finally {
        Foo.decrementCounter();
      }
    }
  });
}

问题是如果 Runnable r 创建Foo的多个实例。您必须以某种方式跟踪线程创建的实例数。您可以使用 ThreadLocal< Integer> ,然后在<$ c $中调用 decrementCounter() c>最后阻止,适当的次数。请参阅下面的完整工作示例。

The problem with this is if the Runnable r creates multiple instances of Foo. You'd have to somehow track how many instances the thread created. You could do so using a ThreadLocal<Integer>, and then call decrementCounter(), in the finally block, the appropriate number of times. See below for a complete, working example.

如果可以避免它,则不应该依赖GC的行为,因为它非常难以预测!如果你坚持要处理垃圾收集器,那么你应该使用引用队列 - 并且要正确使用它,你应该研究对象可达性的概念: http://docs.oracle.com/javase/7/docs /api/index.html?java/lang/ref/package-summary.html

If you can avoid it, you should not rely on the behavior of the GC as it is quite impredictable! If you insist into dealing with the Garbage Collector, then you should use reference queues -- and to use it properly, you should study the concept of object reachability: http://docs.oracle.com/javase/7/docs/api/index.html?java/lang/ref/package-summary.html

作为最后一点,如果我正在采访你,我' d试图让你意识到你提出的代码并不完全满足要求:你必须使类 final ,或方法 incrementCount() final private 。或者,更容易,您可以在实例初始化程序块中增加计数:无需考虑在子类中重写的方法或新增的构造函数而不增加计数。

As a final note, if I were interviewing you, I'd try to make you realize that the code you propose does not perfectly satisfy the requirements: you'd have to make the class final, or the method incrementCount() final or private. Or, easier, you could increment the count in an instance initializer block: no need to think about methods being overriden in subclasses or newly added constructors not incrementing the count.

一个完整的例子:

public class Foo {
  private static final AtomicInteger liveInstances = new AtomicInteger(0);
  private static final ThreadLocal<Integer> threadLocalLiveInstances = new ThreadLocal<Integer>() {
    @Override protected Integer initialValue() { return 0; }
  }

  // instance initializer (so you won't have problems with multiple constructors or virtual methods called from them):
  {
    liveInstances.incrementAndGet();
    threadLocalLiveInstances.set(threadLocalLiveInstances.get() + 1);
  }

  public static int getTotalLiveInstances() {
    return liveInstances.get();
  }

  public static int getThreadLocalLiveInstances() {
    return threadLocalLiveInstances.get();
  }

  public static void decrementInstanceCount() {
    threadLocalLiveInstances.set(threadLocalLiveInstances.get() - 1);
    liveInstaces.decrementAndGet();
  }

  // ... rest of the code of the class ...
}

class FooCountingThreadFactory implements ThreadFactory {
  public Thread newThread(final Runnable r) {
    return new Thread(new Runnable() {
      @Override public void run() {
        try {
          r.run();
        } finally {
          while (Foo.getThreadLocalLiveInstances() > 0) {
            Foo.decrementInstanceCount();
          }
        }
      }
    });
  }
}

这样,你可以将这个ThreadFactory提供给一个线程例如,或者当你想构建一个线程时你可以自己使用它:(new FooCountingThreadFactory())。newThread(job);

This way, you can feed this ThreadFactory to a thread pool, for example, or you can use it yourself when you want to build a thread: (new FooCountingThreadFactory()).newThread(job);

无论如何,这种方法仍然存在问题:如果一个线程创建了 Foo 的实例并将它们存储在全局范围内(读取: static fields),然后这些实例在线程死亡后仍然处于活动状态,并且计数器将全部减少为0。

Anyways, there's still a problem with this approach: if a thread creates instances of Foo and stores them on global scope (read: static fields), then these instances will still be alive after the thread has died, and the counter will all the same be decremented to 0.

这篇关于如何在Java中实现对象计数器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆