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

发布于 2024-09-14 17:39:20 字数 831 浏览 3 评论 0原文

在对象构造函数中启动线程池是否安全?我知道你不应该从构造函数启动一个线程,关于“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 服务器中的指令集对象,但我的想法是拥有一个单独的类,因为它使整个代码更具可读性,因为每个类只专注于做一件特定的事情。

想法?建议?

谢谢

Is it safe to start a thread pool in an objects constructor? I know that you shouldn't start a thread from a constructor, something about the "this" pointer escaping (I don't exactly understand this, but will do some more searches to try and figure it out).

The code would look something like this:

private ExecutorService pool;

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

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

If that doesn't work, i could just create this class as a Runnable and start it in a new thread. However, that seems like it would be adding an unnecessary thread to the program where it doesn't really need one.

Thanks.

EDIT:

Thanks for the replies everyone, they definitely helped make sense of this.

As per the code, in my mind it makes sense that this constructor creates the thread pool, but let me explain what specifically this code is doing, because i may be thinking about this in a weird way.

The entire point of this object is to take "Instruction Sets" objects, and act on them accordingly. The instruction sets come from clients connected to a server. Once a full instruction set is received from a client, that instruction set is sent to this object (handler) for processing.

This handler object contains a reference to every object that an instruction set can act upon. It will submit the instruction set to a thread pool, which will find which object this instruction set wants to interact with, and then handle the instruction set on that object.

I could handle the instruction set object in the IO server, but my thoughts are having a separate class for it makes the entire code more readable, as each class is focusing on doing only one specific thing.

Thoughts? Advice?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

樱花细雨 2024-09-21 17:39:20

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

基本上让“this”引用转义通常令人讨厌,但并非普遍如此。在某些情况下它是安全的。请小心。

话虽如此,让构造函数启动线程可能会被视为在构造函数内执行过多操作。很难说它在这种情况下是否合适 - 我们对您的代码在做什么了解不够。

编辑:是的,阅读了额外的信息后,我认为这是可以的。您可能还应该有一种方法来关闭线程池。

Your sample code doesn't let "this" escape at all. It's reasonably safe to start a new thread in a constructor (and even use this as the Runnable, which you don't in this example) so long as you're sure that you've already initialized the object as far as the new thread will need it. For example, setting a final field which the new thread will rely on after starting the thread would be a really bad idea :)

Basically letting the "this" reference escape is generally nasty, but not universally so. There are situations in which it's safe. Just be careful.

Having said that, making a constructor start a thread might be seen as doing too much within the constructor. It's hard to say whether it's appropriate in this case or not - we don't know enough about what your code is doing.

EDIT: Yup, having read the extra information, I think this is okay. You should probably have a method to shut down the thread pool as well.

金兰素衣 2024-09-21 17:39:20

我同意乔恩的观点。

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

I agree with Jon.

Furthermore, let me point that you're not actually starting any actions on the thread pool in the constructor. You're instantiating the thread pool, but it has no tasks to run at that point. Therefore, as written, you're not going to have something start operating on this instance before it finishes construction.

如果没有 2024-09-21 17:39:20

听起来线程池将由对象拥有和使用;线程不会从对象中传递出去。如果是这样的话,那应该不是问题。

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

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

更多细节可能会有所帮助。

It sounds like the thread pool would be owned and used by the object; threads wouldn't be pass out of the object. If that's the case, it shouldn't be an issue.

Constructors create an object and initialize its state. I can't imagine a use case where long-running processes are required to do so.

I can see where an object might interact with a thread pool to accomplish a task, but I don't see the need for that object to own the thread pool.

More details might help.

还在原地等你 2024-09-21 17:39:20

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

如果您走这条路,您将必须付出额外的努力来提供以下保证:

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

->

MyThreadPoolContainer container =
    new MyThreadPoolContainer( ... args to initialize the object... );

try
{
  methodThatUsesContainer( container );
}
finally
{
  container.releaseResources( );
}
  1. 记录对象构造函数分配有限的资源,并且必须显式调用析构函数方法以防止泄漏。

I think it's OK to start a thread pool in the constructor of the object as long as that object fully manages the lifetime of that thread pool.

If you go this path, you will have to work extra hard to provide the following guarantees:

  1. If you constructor throws any exception ( both Runtime and checked ), you must have cleanup code in the constructor that shuts down the thread pool. If you don't do this and create a thread pool with non-daemon threads then, for example, a little console program that uses your object may stay up forever, leaking valuable system resources.
  2. You need to provide something that I call destructor method, similar to close in Java I/O. I usually call it releaseResources. Notice that finalize is not a substitute for this method, because it is called by GC, and for an object with reasonably small memory footprint it may never be called.
  3. When using this object follow this pattern

->

MyThreadPoolContainer container =
    new MyThreadPoolContainer( ... args to initialize the object... );

try
{
  methodThatUsesContainer( container );
}
finally
{
  container.releaseResources( );
}
  1. Document that object constructor allocates limited resources and the destructor method has to be called explicitly to prevent their leakage.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文