始终保持固定的线程数

时间:2014-07-05 04:45:37

标签: java thread-safety threadpool threadpoolexecutor

我正在从执行程序服务创建固定的线程池。但是如果出现一些运行时异常或错误(OutOfMemory Error),则线程将死亡并且线程数将继续减少,并且一次线程数将为零,这称为静默线程查杀。

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

任何建议都很明显。

1 个答案:

答案 0 :(得分:0)

SingleThreadExecutor的ApiDoc声明如下:"但是请注意,如果这个单线程由于在关闭之前执行期间的故障而终止,那么如果需要执行后续操作,则新的一个线程将取代它任务"

这似乎也适用于具有多个线程的ThreadPools(参见下面的演示程序)。因此,除非程序运行inro一个真正的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);
    }
}
}