是指计数好的设计

时间:2011-08-03 20:54:35

标签: java reference-counting

我们正在开发一个应用程序容器,它使用引用计数作为跟踪收到的请求和发送的响应的机制。引用计数用于允许容器的正常关闭,即if (refCount == 0) shutdown;

对于每个请求以及待处理的响应,引用计数都会递增。只有在应用程序接受了请求后,引用计数才会递减,并且只有在应用程序发送了有效响应后才会递减。 所以这是我的问题,在这种情况下引用计算是一个好的设计决策,比如保持RequestContext仅在Application / Container发送响应时才关闭?

由于该软件是用Java实现的,我正在研究Java中的其他选项并且遇到了这篇文章http://weblogs.java.net/blog/2006/05/04/understanding-weak-references,这让我觉得尝试利用ReferenceQueue可能是另一种做法

2 个答案:

答案 0 :(得分:1)

这实际上是一种非常巧妙的方式。您还应该另外使用ThreadLocal(如果您的请求 - 响应管道将由单个线程处理)

基本上,当您收到请求时。将带有WeakRefernce的ThreadLocal设置为您的请求对象(或请求的某些属性,例如用户ID等)。然后,您可以在处理管道中的任何位置get()对象。

如果您使用ThreadPool of workers来处理请求,请确保从线程的ThreadLocal中取消设置Weak Reference对象,以便不再存在该对象的引用。如果您为每个请求生成一个新线程,您甚至不需要这样做。当线程死亡时,对象将自动返回到referenceQueue(因为没有实时引用指向该对象)

答案 1 :(得分:1)

请注意,您将支付具有性能命中率的计数器。实际上,您需要为每个请求IFF使用并发线程来为请求提供内存屏障。 (内存屏障指令通常最多需要200条指令。)

根据你的问题,你似乎甚至不想要一个计数器,而是一个二进制标志,表明是否有任何活动请求,例如一个requestsInProgress标志。当标志值为false时,您可以“优雅地关闭”。

如果您的容器主要公开网络端点,例如REST / HTTP然后我强烈建议您考虑NIO并使用单线程调度机制来线性化容器外围的req / rep。 (您可以使用java.util.concurrent中的并发队列对这些队列进行排队并扇出到N个处理线程。

[NIO subsystem] <-{poll}-[Selector(accept/read)/dispatch thread] => [Q:producer/consumer pattern 1:N]
[NIO subystem] <-{poll}-[Selector(write)/responder thread] <= [Q:producer/consumer N:1]

效益?

如果您使用相同的线程进行分派和响应,则不会涉及内存障碍 - 该线程将固定到核心,并且您的标志将独占其缓存行:

e.g。

发送队列请求后

:       增量req_in_progress

响应者出现响应后:       减少req_in_progress

在关机时需要共享内存同步,但这比每次请求产生的成本要好得多,因为您只需在实际需要时付费。

如果性能根本不是问题,那么为什么不使用AtomicInteger作为计数器并将其放在全局上下文中呢?