8

我的 Java.NIO 套接字服务器中有一个线程池。我有时会收到运行时错误,例如Connection reset by peerorBroken Pipe等​​。

我的问题是:抛出异常时线程是否被杀死?如果是 - 是否在线程池中创建了一个新线程来代替被杀死的线程?

这是我的线程管理器:

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));
    }   
}
4

3 回答 3

12

当您使用ExecutorService创建线程池时。

所以的,ExecutorService.newFixedThreadPool(..)确保如果线程被任何异常/错误杀死并且有足够的任务等待线程,线程数是恒定的。以下来自 java doc 的文本清楚地说明了这一点:

直接来自 java 文档:newFixedThreadPool

创建一个线程池,该线程池重用在共享无界队列上运行的固定数量的线程。在任何时候,最多 nThreads 个线程将是活动的处理任务。如果在所有线程都处于活动状态时提交了其他任务,它们将在队列中等待,直到有线程可用。如果任何线程在关闭之前的执行过程中由于失败而终止,如果需要执行后续任务,新的线程将取代它。池中的线程将一直存在,直到显式关闭。

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

于 2013-01-19T14:05:17.670 回答
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);
}

[编辑] - 忘记了另一个问题。事实上,异常确实会杀死 Worker 线程——您需要在内部处理错误。有关详细信息,请查看 java.util.concurrent.ThreadPoolExecutor.Worker 类。它的 runTask 方法值得一试。

于 2013-01-19T14:13:06.747 回答
0

我的问题是:当捕获到错误时线程会被杀死吗?

如果是这样 - 线程池用新线程填充它在池中的位置?

如果池中的一个线程死亡,则创建的执行Executors.newFixedThreadPool程序将创建一个新线程,因此您问题第二部分的答案是肯定的。至于第一部分,不看 and 的代码是不可能的MessagesProcessorLogoutClient但是考虑到任何死线程都会被替换,这并不重要。如果MessagesProcessorLogoutClient在内部捕获并记录异常

public void run() {
  try {
    // do stuff
  } catch(Exception e) {
    e.printStackTrace();
  }
}

然后异常不会传播到run方法之外,因此不会杀死正在运行任务的线程,因此它将能够返回到池中。但是如果他们没有捕捉到异常,并且他们允许将 a从方法RuntimeException中抛出,run那么线程将会死掉(并被一个新的替换)。

于 2013-01-19T14:10:18.610 回答