Java线程池 - 线程是否会被更新?

8
我在我的Java.NIO套接字服务器中使用了线程池。有时我会收到运行时错误,比如“Connection reset by peer”或“Broken Pipe”等。
我的问题是:当抛出异常时,线程是否被杀死?如果是的话,线程池中会创建一个新的线程来代替被杀死的线程吗?
这是我的ThreadManager:
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ThreadsManager {

    private ExecutorService threadPool = null;
    private LiveConnectionsManager liveConnectionsManager;
    private int threadPoolSize = 35; //number of tasks thread

    public ThreadsManager(LiveConnectionsManager liveConnectionsManager) {
        this.liveConnectionsManager = liveConnectionsManager;
        threadPool = Executors.newFixedThreadPool(threadPoolSize);
        ServerActions.threadPool = threadPool;
    }

    public void processNewMessage(SocketChannel socketChannel, Client client)
    {
        threadPool.execute(new MessagesProcessor(socketChannel, client, liveConnectionsManager));
    }

    public void closeConnection(SocketChannel socketChannel, Client client) {
        threadPool.execute(new LogoutClient(socketChannel, client, null));
    }   
}
3个回答

12

当您使用 ExecutorService 创建线程池时。 因此,是的ExecutorService.newFixedThreadPool(..)确保线程数保持不变,如果它们被任何异常/错误杀死,并且有足够的任务等待线程。下面来自java文档的文本清楚地说明了这一点:

从java文档中直接引用:newFixedThreadPool

创建一个线程池,它重用一定数量的线程,这些线程从共享的无限制队列中操作。在任何时候,最多只有nThreads个线程处于活动状态以处理任务。如果在所有线程都处于活动状态时提交了额外的任务,则它们将在队列中等待,直到有线程可用。如果任何线程在关闭之前由于执行期间的故障而终止,则如果需要执行后续任务,将有新的线程代替它。池中的线程将存在直到明确关闭。

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool(int)


只是为了确认 - 当线程出现异常时,它会被终止吗?还是可以返回空闲状态? - Asaf Nevo
根据规范所述,如果在执行过程中出现任何故障并且线程被终止,则会创建一个新的线程。 - rai.skumar
它说“最多”,因为可用的线程可能更少。线程仅在需要时才被创建,并且在未使用时不会被池终止。但是,只有当任务在队列中等待并且可用的线程少于最大线程数时才会发生创建-因此,线程数 不是 常数。 - theadam
同意。只有在需要线程时,执行者才会创建线程,直到达到设置的数量。所以我指的是在空闲状态下,当所有线程都已经创建时,执行者会确保池中有可用线程。我修改了我的评论以使其更清晰。谢谢@theadam。 - rai.skumar
这仍然不正确。即使 corePoolSize 饱和并且在任务执行期间一些线程被终止,如果没有排队的内容,新线程仍然不会被创建。您现在的答案表明,在创建了所有 corePoolSize 线程之后,ThreadPoolExecutor 确实会立即创建一个新线程,如果其中一个活动线程死亡。 - theadam
所以,是的,ExecutorService.newFixedThreadPool(..)确保线程数量恒定,如果有的话。有没有一种方法可以模拟它无法创建线程的情况? - Jigar Shah

4
ThreadPoolExecutor 可以根据您选择的设置(通过构造函数或所使用的助手方法传递)来管理线程数。它的工作方式就像在 ThreadPoolExecutor javadoc 中描述的那样。
从以下构造函数中,最有趣的参数是 corePoolSizemaximumPoolSizecorePoolSize 是将保持活动状态的最少线程数。如果杀死一个线程,并且由于此原因线程数下降到低于此数字,将会启动新的线程[1](在某个时间点)。 maximumPoolSize 是池中线程的最大数量。如果这比 corePoolSize 更高,则您的池可能会拥有比您在 corePoolSize 参数中指定的更多的线程。此时,如果其中一个线程死亡并且活动线程的数量不会降至 corePoolSize 数字以下,则不会创建新线程。
通过 Executors 帮助类创建的固定线程池具有 corePoolSize == maximumPoolSize,因此服务确实将始终确保可用相同数量的线程[1](当需要时)。
[1] 重要提示:线程的创建是“按需”进行的 - 也就是说,如果线程死亡并且队列中没有任务,则在不需要的情况下将不会创建线程(通过在已有可用线程之上排队而需要线程)。
/**
 * Creates a new <tt>ThreadPoolExecutor</tt>( ... cut irelevant part ... )
 *
 * @param corePoolSize the number of threads to keep in the
 * pool, even if they are idle.
 * @param maximumPoolSize the maximum number of threads to allow in the
 * pool.
 * ( ... cut irelevant part ... )
 */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

[编辑] - 忘记另一个问题了。 确实,异常会终止工作线程 - 您需要在内部处理错误。 有关详细信息,请检查java.util.concurrent.ThreadPoolExecutor.Worker类。其中的runTask方法值得一看。


你复制粘贴了整个Javadoc! - Narendra Pathai
仅从一个构造函数来看,剪掉无关部分真的有帮助吗? - theadam

0
我的问题是:当捕获到错误时,线程是否会被终止?
如果是的话,线程池会用新线程填充它在池中的位置吗?
Executors.newFixedThreadPool创建的执行器将在池中的任何一个线程死亡时创建一个新线程,因此您的问题的第二部分的答案是肯定的。至于第一部分,如果没有看到MessagesProcessorLogoutClient的代码,就无法确定,但是考虑到任何死亡的线程都将被替换,这并不重要。如果MessagesProcessorLogoutClient在内部捕获和记录异常,则不管怎样都没关系。
public void run() {
  try {
    // do stuff
  } catch(Exception e) {
    e.printStackTrace();
  }
}

如果捕获了异常,那么异常就不会传播到run方法之外,因此不会终止运行任务的线程,因此它将能够返回到池中。但是,如果他们没有捕获异常,并且允许RuntimeExceptionrun方法中抛出,则线程将死亡(并被新线程替换)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接