2014-07-05 49 views
1

我从执行程序服务创建固定线程池。但是如果有一些运行时异常或错误(OutOfMemory Error)出现,那么线程将会死亡,并且线程数量会持续减少,并且一次线程数将为零,这就是所谓的无声线程查杀。保持固定线程数始终为

一种方法是捕捉throwable(这不是一个好习惯),以避免线程kill。有什么办法可以永远保持固定的线程数?如果线程杀死/死亡,那么一个新的线程应该自动产生,这样我们总是有固定数量的线程。

任何建议是可观的。

+0

你能提供一个沉默线程的例子杀人?我无法复制它。我更新了[这个答案](http://stackoverflow.com/a/24697277/3080094)中的代码,在第一个'Runnable'的末尾抛出了一个'OutOfMemoryError',但程序仍然运行正常 - ThreadPoolExecutor只是丢弃旧的线程并创建一个新线程。 – vanOekel

+0

@vanOekel您确定ThreadPool执行程序在旧线程死亡时创建新线程。我从未在任何地方找到过。任何链接都会非常有帮助。 – Naveen

+0

那么更新的代码显示它发生了。所以让我们来回顾一下:当池中的某个线程不再可用时,您能否显示ThreadPoolExecutor不会启动新线程,或者提供解释何时发生的文档链接? – vanOekel

回答

0

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

这似乎也适用于带有多个线程的ThreadPools(请参阅下面的演示程序)。因此,除非程序运行真正的OutOfMemoryError(例如,不是偶然会分配太大的字节数组),否则将不会发生无声的线程杀死。如果程序运行到一个真正的OutOfMemoryError那么我认为可以做很多事情:由于内存不足,必须执行的所有类型的语句(在最后的块中)可能突然无法执行,并且可能使程序处于不一致的状态(如不带线程的ThreadPool)。

下面的演示程序显示了所有任务的执行和THEAD,名称显示新的线程由线程池创建:

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