【问题标题】:is reference counting good design引用计数是好的设计吗
【发布时间】:2011-08-03 20:54:34
【问题描述】:

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

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

由于该软件是用 Java 实现的,我一直在研究 Java 中的其他选项并偶然发现了这篇文章,http://weblogs.java.net/blog/2006/05/04/understanding-weak-references,这让我认为尝试利用 ReferenceQueue 可能是实现此目的的另一种方法。

【问题讨论】:

  • 我认为您在这里重载了“引用计数”一词。如果将请求对象分配给新引用,则不会增加引用计数,对吗?我认为“参考”根本不属于这里的术语。

标签: java reference-counting


【解决方案1】:

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

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

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

【讨论】:

  • “您还应该使用 ThreadLocal(如果您的请求 - 响应管道将由单个线程处理)”。请澄清您的意思是容器是单线程的。如果是的话,那么使用ThreadLocal其实就是在浪费CPU周期。
  • 哦,绝对不是……我说的是多线程容器……请原谅我的措辞中的任何错误含义……
  • 感谢您的澄清。请原谅我对你的误解!
【解决方案2】:

请注意,您需要为性能命中的计数器付费。实际上,如果您使用并发线程为请求提供服务,则您需要为每个请求 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]

好处?

如果您对调度和响应者使用相同的线程,则不涉及内存屏障——线程将被固定到一个核心,并且您的标志将独占其缓存行:

例如

在调度队列请求之后: 递增req_in_progress

在响应者出列响应后: 递减req_in_progress

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 2015-02-23
    • 1970-01-01
    • 2011-09-13
    • 2010-10-31
    • 1970-01-01
    相关资源
    最近更新 更多