Я создаю пул фиксированных потоков из службы-исполнителя. Но если возникнет какое-то исключение или ошибка при запуске (ошибка OutOfMemory), поток будет мертв, и количество потоков будет продолжать уменьшаться, и за один раз количество потоков будет равно нулю, что называется убийством беззвучного потока.
Один из способов - поймать бросок (что не является хорошей практикой), чтобы избежать уничтожения потока. Есть ли способ поддерживать постоянное число потоков. Если поток убивает/умирает, то новый поток должен автоматически появляться так, чтобы мы фиксировали количество потоков всегда.
Любые предложения заметны.
В ApiDocs для SingleThreadExecutor
указано следующее: "Обратите внимание, что если этот единственный поток завершается из-за сбоя во время выполнения перед завершением работы, новый будет SingleThreadExecutor
, если это необходимо для выполнения последующих задач".
Это также относится к ThreadPools с несколькими потоками (см. Демонстрационную программу ниже). Поэтому, если программа не запускает inro реальный OutOfMemoryError
(например, не случайный, когда выделен слишком большой байт-массив), тихий поток убивает не произойдет. Если программа работает в реальном OutOfMemoryError
то я не думаю, что многое можно сделать: все виды операторов, которые должны быть выполнены (в финальных блоках), могут неожиданно не выполняться из-за нехватки памяти, и это может оставить программу в несогласованное состояние (например, ThreadPool без потоков).
В приведенной ниже демонстрационной программе показаны все задачи, которые выполняются, и имена thead показывают, что новые потоки создаются 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);
}
}
}
OutOfMemoryError
в конце первогоRunnable
но программа все еще работает нормально -ThreadPoolExecutor
просто отбрасывает «старый» поток и создает новый.