Depth parsing the exception handling mechanism of Java thread pool #3

Source: Internet
Author: User
Tags throwable

Objective

Today, small partners encounter a small problem, the thread pool submitted by the task if there is no catch exception, then will be thrown where to go, before it did not study, in the principle of seeking truth from facts, looked at the code.

Text small problem

Consider the following code, what is the difference? Can you guess if there's an anomaly? Where is the word if it is called? :

        ExecutorService threadPool = Executors.newFixedThreadPool(1);        threadPool.submit(() -> {            Object obj = null;            System.out.println(obj.toString());        });        threadPool.execute(() -> {            Object obj = null;            System.out.println(obj.toString());        });
SOURCE parsing

We will look at the code below, in fact, we have submitted the past runnable packaging into a future

    Public future<?> Submit (Runnable Task) {if (task = = null) throw new NullPointerException ();        runnablefuture<void> ftask = newtaskfor (task, NULL);        Execute (ftask);    return ftask; } protected <T> runnablefuture<t> newtaskfor (Runnable Runnable, T value) {return new futuretask<    T> (runnable, value);        } public Futuretask (Runnable Runnable, V result) {this.callable = executors.callable (Runnable, result);       This.state = NEW; Volatile modifier to ensure visibility under multi-threading, can look at Java memory model} public static <T> callable<t> callable (Runnable task, T result)        {if (task = = null) throw new NullPointerException ();    return new runnableadapter<t> (task, result);        } Static final class Runnableadapter<t> implements callable<t> {final Runnable task;        Final T result;            Runnableadapter (Runnable task, T result) {this.task = task; This.rEsult = result;            } public T-call () {task.run ();        return result; }    }

The next step is actually committed to the queue for the thread pool dispatch processing:

    /**    * 代码还是很清爽的,一个很典型的生产者/消费者模型,    * 这里暂不纠结这些细节,那么如果提交到workQueue成功的话,消费者是谁呢?    * 明显在这个newWorker里搞的鬼,同样细节有兴趣可以自己再去研究,这里我们会发现    * 核心就是Worker这个内部类    */    public void execute(Runnable command) {        if (command == null)            throw new NullPointerException();        int c = ctl.get();        if (workerCountOf(c) < corePoolSize) {            if (addWorker(command, true))                return;            c = ctl.get();        }        if (isRunning(c) && workQueue.offer(command)) {            int recheck = ctl.get();            if (! isRunning(recheck) && remove(command))                reject(command);            else if (workerCountOf(recheck) == 0)                addWorker(null, false);        }        else if (!addWorker(command, false))            reject(command);    }

Then look at the process of thread pool core:

Private Final class Worker extends Abstractqueuedsynchronizer implements runnable{/** Delegates ma        In run loop to outer runworker */public void run () {runworker (this);        }}final void Runworker (Worker w) {Thread wt = Thread.CurrentThread ();        Runnable task = W.firsttask;        W.firsttask = null; W.unlock ();        Allow interrupts Boolean completedabruptly = true; The try {//gettask () method attempts to fetch data from the queue while (task! = NULL | |                (Task = Gettask ()) = null) {W.lock ();                     if (Runstateatleast (Ctl.get (), STOP) | | (thread.interrupted () && runstateatleast (Ctl.get (), STOP)))                &&!wt.isinterrupted ()) wt.interrupt ();                    try {//can override this method to log beforeexecute (WT, task) such as buried point;                    Throwable thrown = null;  try {                      Straightforward and straightforward, call the Run Method 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); }    }
Submit the Way

Then we can here is the direct call to the Run method, first look at the way of submit, we know that the final pass is a futuretask, that is to call the Run method here, we look at the implementation:

    public void Run () {if ' state! = NEW | | !            Unsafe.compareandswapobject (this, runneroffset, NULL, Thread.CurrentThread ()))        Return            try {callable<v> c = callable;                if (c! = null && state = = NEW) {V result;                Boolean ran;                    try {result = C.call ();                ran = true;                    } catch (Throwable ex) {result = null;                    ran = false;                    。。。                SetException (ex);            } if (ran) set (result); }} finally {//omit} protected void SetException (Throwable t) {if (Unsafe.compareandswapin T (this, Stateoffset, NEW, completing)) {outcome = t;//assigns this variable unsafe.putorderedint (this, stateoffs ET, exceptional); Final State FinishcoMpletion (); }    }

You can see that it is similar to swallowing directly, so that we can get it when we call the Get () method, for example, we could rewrite the AfterExecute method to get the actual exception:

protected void afterExecute(Runnable r, Throwable t) {          super.afterExecute(r, t);          if (t == null && r instanceof Future<?>) {            try {              //get这里会首先检查任务的状态,然后将上面的异常包装成ExecutionException              Object result = ((Future<?>) r).get();            } catch (CancellationException ce) {                t = ce;            } catch (ExecutionException ee) {                t = ee.getCause();            } catch (InterruptedException ie) {                Thread.currentThread().interrupt(); // ignore/reset            }          }          if (t != null){            //异常处理            t.printStackTrace();          }        }
How to execute

So what's the difference if it's a direct exeture way? In this way the passing of the past is directly runnable, so it will be thrown directly:

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

So where does the exception go from here, let's see what the JVM is dealing with:

if (!DESTROY_VM | | Jdk_version::is_jdk12x_version ()) {//Jsr-166:change call from from threadgroup.uncaughtexception to//Java.lang. Thread.dispatchuncaughtexception if (Uncaught_exception.not_null ()) {//If there is an uncaught exception Handle group (this, Java_lan      G_thread::threadgroup (Threadobj ()));        {Klasshandle Recvrklass (THREAD, Threadobj->klass ());        Callinfo Callinfo;        Klasshandle thread_klass (thread, Systemdictionary::thread_klass ());            /* This is similar to a method table and will actually call the Thread#dispatchuncaughtexception method template (Dispatchuncaughtexception_name, "Dispatchuncaughtexception") */Linkresolver::resolve_virtual_call (callinfo, thread                                           OBJ, Recvrklass, Thread_klass, Vmsymbols::d ispatchuncaughtexception_name (), Vmsymbols::throwable_void_signature (), Kla Sshandle (), False, False, THREAD);       Clear_pending_exception;        Methodhandle method = Callinfo.selected_method ();          if (Method.not_null ()) {javavalue result (t_void);                                  Javacalls::call_virtual (&result, Threadobj, Thread_klass,                                   Vmsymbols::d ispatchuncaughtexception_name (), Vmsymbols::throwable_void_signature (),        Uncaught_exception, THREAD);          } else {Klasshandle thread_group (thread, Systemdictionary::threadgroup_klass ());          Javavalue result (t_void);                                  Javacalls::call_virtual (&result, group, Thread_group,                                  Vmsymbols::uncaughtexception_name (), Vmsymbols::thread_throwable_void_signature (), Threadobj,//ARG 1 Uncaught_exceptioN,//ARG 2 THREAD);          } if (has_pending_exception) {Resourcemark rm (this);                jio_fprintf (Defaultstream::error_stream (), "\nexception:%s thrown from the Uncaughtexceptionhandler" "In Thread \"%s\ "\ n", Pending_exception ()->klass ()->external_name (), get_th          Read_name ());        Clear_pending_exception; }      }    }

You can see that this will eventually call the Thread#dispatchuncaughtexception method:

    private void dispatchUncaughtException(Throwable e) {        //默认会调用ThreadGroup的实现        getUncaughtExceptionHandler().uncaughtException(this, e);    }

?

    public void uncaughtException(Thread t, Throwable e) {        if (parent != null) {            parent.uncaughtException(t, e);        } else {            Thread.UncaughtExceptionHandler ueh =                Thread.getDefaultUncaughtExceptionHandler();            if (ueh != null) {                ueh.uncaughtException(t, e);            } else if (!(e instanceof ThreadDeath)) {                //可以看到会打到System.err里面                System.err.print("Exception in thread \""                                 + t.getName() + "\" ");                e.printStackTrace(System.err);            }        }    }

If the environment is Tomcat, it will eventually hit Catalina.out:

Summarize

The recommended way to handle exception handling for thread pools, including threads:

1 Direct Try/catch, the personal basic is in this way

2 threads rewrite the entire method directly:

          Thread t = new Thread();          t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {              public void uncaughtException(Thread t, Throwable e) {                 LOGGER.error(t + " throws exception: " + e);              }           });        //如果是线程池的模式:           ExecutorService threadPool = Executors.newFixedThreadPool(1, r -> {               Thread t = new Thread(r);               t.setUncaughtExceptionHandler(                   (t1, e) -> LOGGER.error(t1 + " throws exception: " + e));               return t;           });

3 You can also override the protected void afterExecute(Runnable r, Throwable t) { } method directly

Depth parsing the exception handling mechanism of Java thread pool #3

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.