【问题标题】:Maintain Fixed Number Of Threads always始终保持固定数量的线程
【发布时间】:2014-08-26 07:27:14
【问题描述】:

我正在从执行器服务创建固定线程池。但是如果出现一些运行时异常或错误(OutOfMemory Error),那么线程就会死掉,线程数会不断减少,并且有一次线程数会为零,这就是所谓的静默线程杀。

一种方法是捕获 throwable(这不是一个好习惯)以避免线程终止。有什么方法可以让我们始终保持固定数量的线程。如果线程终止/死亡,则应自动生成一个新线程,以便我们始终拥有固定数量的线程。

任何建议都是值得赞赏的。

【问题讨论】:

  • 你能提供一个静默线程杀死的例子吗?我无法重现它。我已经更新了this answer 中的代码,在第一个Runnable 的末尾抛出了一个OutOfMemoryError,但程序仍然运行良好——ThreadPoolExecutor 只是丢弃了“旧”线程并创建了一个新线程。
  • @vanOekel 您确定 ThreadPool Executor 在旧线程死亡时创建新线程。我在任何地方都找不到这个。任何链接都会非常有帮助。
  • 更新后的代码显示它发生了。所以让我们扭转局面:当池中的一个线程不再可用时,您能否证明ThreadPoolExecutor 不会启动新线程,或者提供解释何时发生这种情况的文档链接?

标签: java thread-safety threadpool threadpoolexecutor


【解决方案1】:

SingleThreadExecutor 的 ApiDocs 声明如下:“但请注意,如果此单线程在关闭前的执行过程中因故障而终止,如果需要执行后续任务,则新线程将取代它。”

这似乎也适用于具有多个线程的 ThreadPools(参见下面的演示程序)。因此,除非程序以真正的OutOfMemoryError 运行(例如,分配了太大的字节数组不是偶然的),否则不会发生静默线程终止。如果程序运行到真正的OutOfMemoryError,那么我认为无能为力:必须执行的各种语句(在最终块中)可能由于内存不足而突然无法执行,并且可能会离开程序处于不一致的状态(例如没有线程的 ThreadPool)。

下面的演示程序显示所有任务都已执行,并且 thead-names 显示新线程是由 ThreadPool 创建的:

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class SilentKillThread {

public static void main(String[] args) {

    try {
        new SilentKillThread().runTest();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

static int MAX_TASKS = 3;
static long SLEEP_TIME_MS = 400;

AtomicInteger tasksDoneCount = new AtomicInteger();

public void runTest() throws Exception {

    ThreadPoolExecutor tp = new ThreadPoolExecutor(MAX_TASKS, MAX_TASKS,
            60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>());

    for (int i = 0; i < MAX_TASKS; i++) {
        tp.execute(new FailingTask());
    }
    for (int i = 0; i < MAX_TASKS; i++) {
        tp.execute(new SleepingTask());
    }
    tp.shutdown();
    if (tp.awaitTermination(SLEEP_TIME_MS * 4, TimeUnit.MILLISECONDS)) {
        System.out.println("Finished");
    } else {
        System.out.println("Finished but threadpool still active.");
    }
    System.out.println("Tasks done: " + tasksDoneCount.get());
}

class FailingTask implements Runnable {

    @Override 
    public void run() { 
        String tname = Thread.currentThread().getName();
        System.out.println(tname + " Sleeping");
        try { Thread.sleep(SLEEP_TIME_MS); } catch (Exception e) { e.printStackTrace();} 
        int tcount = tasksDoneCount.incrementAndGet();
        System.out.println(tname + " Done sleeping " + tcount);
        throw new OutOfMemoryError();
    }
}

class SleepingTask implements Runnable {

    @Override 
    public void run() { 
        String tname = Thread.currentThread().getName();
        System.out.println(tname + " Sleeping");
        try { Thread.sleep(SLEEP_TIME_MS); } catch (Exception e) { e.printStackTrace();} 
        int tcount = tasksDoneCount.incrementAndGet();
        System.out.println(tname + " Done sleeping " + tcount);
    }
}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-03
    • 1970-01-01
    • 2017-06-20
    • 2013-10-09
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多