【问题标题】:Java - ThreadLocal or Concurrent Object Pool?Java - ThreadLocal 还是并发对象池?
【发布时间】:2024-04-30 02:25:01
【问题描述】:

哪种方法更适合访问非线程安全对象

使用ThreadLocal 对象:

static final ThreadLocal<NonThreadSafeParser> PARSER_THREAD_LOCAL = new ThreadLocal<NonThreadSafeParser>() {
    @Override
    protected NonThreadSafeParser initialValue() {
        return new NonThreadSafeParser();
    }
};

void parse(String input) {
    PARSER_THREAD_LOCAL.get().parse(input);
}

使用并发对象池

static final ConcurrentObjectPool<NonThreadSafeParser> PARSER_POOL = new ConcurrentObjectPool<>();

void parse(String input) {
    NonThreadSafeParser parser = PARSER_POOL.borrow();
    try {
        parser.parse(input);
    } finally {
        PARSER_POOL.release(parser);
    }
}

或您想提供的其他方法?

重要的因素是:

  • 性能
  • 内存使用情况
  • 垃圾回收

一般来说,每种方法的优点缺点是什么?

它们之间有什么明显的区别吗?

谢谢。

编辑

Kryo 使用的Concurrent Object Pools 示例。

【问题讨论】:

  • 闻起来像家庭作业/求职面试!
  • @ParkerHalo 如果是这样呢?对我来说似乎是一个有效的问题
  • @AlexanderDerck 实际上不是。 “您喜欢哪种方法”立即使其有资格以我书中的“主要基于意见”结束。虽然问题本身是无害的,但“家庭作业”的方式却破坏了一个好问题。
  • @Kayaman 实际上是这样。这个问题的目的不是为了任何“求职面试”或“家庭作业!”或诸如此类的事情...实际上,在我当前的项目中,有一种情况我可以同时使用这两个选项,但我想选择最好的一个。
  • @biziclop 你可以自己写ConcurrentObjectPool :)

标签: java performance concurrency thread-local object-pooling


【解决方案1】:

明显的区别当然是你要么有一个对象池,要么每个线程都有一个专用对象。这会产生各种后果,例如 ThreadLocals 可以是完全有状态的,因为它们仅由单个线程使用。池化对象可以是有状态的,但仅在它们被线程签出期间。

Some people think ThreadLocals are evil,即使它们不是,它们仍然要求您在使用它们时成为一个聪明的 cookie。对象池的缺陷和优势在很大程度上取决于存储在其中的实际对象。

因此,总而言之:这取决于并且在某种程度上基于意见。再一次,我们遇到了一个没有绝对答案的软件开发问题,尽管人们喜欢认为我们正在处理一门精确的科学。

【讨论】:

    【解决方案2】:

    一个粗略的经验法则可能是每个线程通常对这些对象拥有多长时间的租约。如果线程应该在(接近)它们一直在主动运行的整个过程中保持这些对象,那么 ThreadLocal 可能是要走的路。另一方面,如果与整个线程的生命周期相比,这些对象只是短暂或间歇性地使用,那么对象池可能是要走的路。

    【讨论】:

      【解决方案3】:

      一般来说,我会使用

      ThreadLocal - 如果该对象仅属于该线程但不能是私有的并且需要跨层访问。它可能是与当前线程相关的上下文。

      ThreadPool - 当我需要共享有限的资源或需要同步多个线程之间的通信时。

      【讨论】: