Java在对象构造函数中启动线程池

时间:2010-08-16 16:50:21

标签: java threadpool

在对象构造函数中启动线程池是否安全?我知道你不应该从构造函数中启动一个线程,关于“this”指针的转义(我不完全理解这一点,但会做更多的搜索来试图找出它)。

代码看起来像这样:

private ExecutorService pool;

public handler()
{
  pool = Executors.newCachedThreadPool();
}

public void queueInstructionSet(InstructionSet set)
{
  pool.submit(new Runnable that handles this instruction set);
}

如果这不起作用,我可以将此类创建为Runnable并在新线程中启动它。但是,这似乎会在程序中添加一个不必要的线程,而不需要它。

感谢。

编辑:

感谢大家的回复,他们肯定有助于理解这一点。

根据代码,在我看来,这个构造函数创建线程池是有意义的,但让我解释一下这个代码的具体用途,因为我可能会以一种奇怪的方式思考这个问题。

此对象的整个要点是采用“指令集”对象,并相应地对其进行操作。指令集来自连接到服务器的客户端。一旦从客户端收到完整的指令集,该指令集就会被发送到该对象(处理程序)进行处理。

此处理程序对象包含对指令集可以处理的每个对象的引用。它将把指令集提交给一个线程池,它将找到该指令集想要与之交互的对象,然后处理该对象上的指令集。

我可以处理IO服务器中的指令集对象,但我的想法是有一个单独的类,因为它使整个代码更具可读性,因为每个类都专注于只做一件特定的事情。

思考?建议?

由于

4 个答案:

答案 0 :(得分:2)

您的示例代码根本不让“this”逃脱。在构造函数中启动一个新线程是相当安全的(甚至使用this作为Runnable,这个例子中你没有这个),只要你确定你已经初始化了对于新线程需要它的对象。例如,在启动线程后设置新线程将依赖的最终字段将是一个非常糟糕的主意:)

基本上让“this”引用转义一般讨厌,但不是普遍的。在某些情况下,它是安全的。小心点。

话虽如此,让构造函数启动一个线程可能会被视为在构造函数中做了太多。在这种情况下很难说它是否合适 - 我们对你的代码做的事情知之甚少。

编辑:是的,已经阅读了额外的信息,我认为这没关系。你应该有一个方法来关闭线程池。

答案 1 :(得分:1)

我同意Jon的观点。

此外,让我指出你实际上并没有在构造函数中的线程池上启动任何操作。您正在实例化线程池,但此时没有任务要运行。因此,正如所写的那样,在完成构建之前,你不会在这个实例上开始运行。

答案 2 :(得分:1)

听起来线程池将由对象拥有和使用;线程不会传递出来。如果是这种情况,那应该不是问题。

构造函数创建一个对象并初始化其状态。我无法想象需要长时间运行的进程的用例。

我可以看到对象可能与线程池交互以完成任务,但我不认为该对象需要拥有线程池。

更多细节可能有所帮助。

答案 3 :(得分:0)

我认为只要该对象完全管理该线程池的生命周期,就可以在对象的构造函数中启动线程池。

如果你走这条路,你将不得不加倍努力提供以下保证:

  1. 如果构造函数抛出任何异常(Runtime和checked),则必须在关闭线程池的构造函数中使用清理代码。如果你不这样做并创建一个带有非守护程序线程的线程池,那么,例如,使用你的对象的一个​​小程序控制台程序可能会永远停留,泄漏宝贵的系统资源。
  2. 您需要提供我称之为destructor方法的内容,类似于Java I / O中的close。我通常称之为releaseResources。请注意,finalize不能替代此方法,因为它是由GC调用的,对于内存占用相当小的对象,它可能永远不会被调用。
  3. 使用此对象时,请遵循此模式
  4. - >

    MyThreadPoolContainer container =
        new MyThreadPoolContainer( ... args to initialize the object... );
    
    try
    {
      methodThatUsesContainer( container );
    }
    finally
    {
      container.releaseResources( );
    }
    
    1. 对象构造函数分配有限资源的文档,必须明确调用destructor方法以防止它们泄漏。