线程池中的线程发生异常被UncaughtExceptionHandler捕获后为啥不能直接重启

先来讲讲我们生成一个任务提交给线程池,线程池是如何启动这个任务的。


上图firstTask就是我们提交的任务,将firstTask作为属性传递给Worker实例化对象,Worker实例化的时候是这样的:


Worker会获取该线程池中的线程工厂把当前Worker对象作为一个Runnable对象传给线程工厂

@Override//自定义方法,非JDK源码
public Thread newThread(Runnable r) {
	Thread thread = new Thread(r,this.threadName);
	MyUncaughtExceptionHandler myUncaughtExceptionHandler = 
			new MyUncaughtExceptionHandler(this.threadName,this.customerFactory);
	thread.setUncaughtExceptionHandler(myUncaughtExceptionHandler);
	return thread;
}

线程工厂将该worker对象包装成一个Thread,给该thread设置一个未捕获异常处理类,返回给Worker的Thread属性,

Worker w = null;
        try {
            final ReentrantLock mainLock = this.mainLock;
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int c = ctl.get();
                    int rs = runStateOf(c);

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }

以上代码中可以看出,如果worker中的thread属性不为空的话,将worker对象加入到工作队列workers中,加入成功后,启动该worker对象中的线程,此时任务开始执行。

      现在我们知道了,如果程序发生异常,那么抛给UncaughtExceptionHandler函数的是worker中的thread线程,thread线程里面的任务实际上是一个worker对象,worker对象中包含我们的自定义Runnable对象呢,这样如果我们在异常捕获中直接将捕获到的线程提交给线程池是不合理的,这也就解释了为什么无法在异常捕获类中直接启动异常线程。

        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
当无法从worker中提取出task时,也就无法执行相关任务了。

猜你喜欢

转载自blog.csdn.net/qq_35689573/article/details/80538842