当我只调用ExecutorService.execute()一次时,为什么有两个线程?

时间:2016-12-21 03:08:51

标签: java multithreading

这是我的代码:

import java.util.concurrent.*;

class ExceptionThread2 implements Runnable {
  public void run() {
    Thread t = Thread.currentThread();
    System.out.println("run() by " + t);
    System.out.println(
      "eh = " + t.getUncaughtExceptionHandler());
    throw new RuntimeException();
  }
}

class MyUncaughtExceptionHandler implements
Thread.UncaughtExceptionHandler {
  public void uncaughtException(Thread t, Throwable e) {
    System.out.println("caught " + e);
  }
}

class HandlerThreadFactory implements ThreadFactory {
  public Thread newThread(Runnable r) {
    System.out.println(this + " creating new Thread");
    Thread t = new Thread(r);
    System.out.println("created " + t);
    t.setUncaughtExceptionHandler(
      new MyUncaughtExceptionHandler());
    System.out.println(
      "eh = " + t.getUncaughtExceptionHandler());
    return t;
  }
}

public class CaptureUncaughtException {
  public static void main(String[] args) {
    ExecutorService exec = Executors.newCachedThreadPool(
      new HandlerThreadFactory());
    exec.execute(new ExceptionThread2());
  }
}

根据Thinking in Java(第4版),结果将是:

HandlerThreadFactory@de6ced creating new Thread
created Thread[Thread-0,5,main]
eh = MyUncaughtExceptionHandler@1fb8ee3
run() by Thread[Thread-0,5,main]
eh = MyUncaughtExceptionHandler@1fb8ee3
caught java.lang.RuntimeException

但在我的机器上,结果是:

HandlerThreadFactory@2e9e53ed creating new Thread
created Thread[Thread-0,5,main]
eh = MyUncaughtExceptionHandler@2fdb8f3a
run() by Thread[Thread-0,5,main]
eh = MyUncaughtExceptionHandler@2fdb8f3a
HandlerThreadFactory@2e9e53ed creating new Thread
created Thread[Thread-1,5,main]
eh = MyUncaughtExceptionHandler@22b1656f
caught java.lang.RuntimeException

我无法弄清楚[Thread-1,5,main]来自哪里?

PS:唯一的区别是前者使用的是Java SE5,但我使用的是Java SE7。

1 个答案:

答案 0 :(得分:0)

我必须查看实现,但它会创建两个线程,因为它尝试始终至少运行一个线程。

它有点混乱的原因是因为发生这种情况的顺序。处理工作者死亡(例如由未捕获的异常引起的死亡)在线程实际死亡之前作为最终行为发生。这意味着操作顺序是

  • 创建工作人员并安排runnable(HandlerThreadFactory.newThread(r)
    • 线程0生活
  • 抛出错误(ExceptionThread2.run()
    • 线程0生活
  • 标记为死的工人(ThreadPoolExecutor.runWorker最终阻止)
    • 线程0生活
  • 可能会创建新工作者(HandlerThreadFactory.newThread(r)
    • 线程0生活
    • Thread-1生活
  • 让异常冒泡到未捕获的异常处理程序(MyUncaughtExceptionHandler.uncaughtException
    • Thread-0 dead
    • Thread-1生活

如果你的书是正确的,那意味着自编写以来实施已经改变。可能因为缓存的线程池通常具有相当不稳定的工作负载,因此保持线程运行会使其更有效。