Bloody lessons - how to use the thread pool submit and execute the right way

Blood background lesson: Use a thread pool of inventory data migration, but there are always a number of data migration fails, no exception log Print

The cause of the murder

I heard that parallelStreamparallel flow is a good thing, because the daily development streammore scenes serial streams, the need to write the migration program just can apply, that is not quickly brought install * it, then do not install now, when . I also know of wit in the JVM background, use of a common fork / join pool to complete these functions, the pool is shared by all parallel streams, by default, fork / join pool will allocate a thread for each processor , the corresponding workaround is to create your own thread pool as

ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
pool.submit(() -> {
            list.parallelStream().collect(Collectors.toList());
        });
复制代码

So from here it landmines planted.

submit or execute

  public static void main(String[] args) throws InterruptedException, ExecutionException {
        final ExecutorService pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
        List<Integer> list = Lists.newArrayList(1, 2, 3, null);
        //1.使用submit
        pool.submit(() -> {
            list.parallelStream().map(a -> a.toString()).collect(Collectors.toList());
        });
        TimeUnit.SECONDS.sleep(3);
        //2.使用 execute
        pool.execute(() -> {
            list.parallelStream().map(a -> a.toString()).collect(Collectors.toList());
        });
        //3.使用submit,调用get()
        pool.submit(() -> {
            list.parallelStream().map(a -> a.toString()).collect(Collectors.toList());
        }).get();
        TimeUnit.SECONDS.sleep(3);
    }
复制代码

The reader to run at the above use cases, you will find separate submitmethod and will not print the error log, use executethe method to print out the error log, but to submitreturn to the FutureJoinTaskcalling get()method will throw an exception. Thus truth, the data present in some batches of dirty data, the null value, the null value to traverse when the exception occurred, but in the exception log submitto catch live process, not print (hurts), is uncaught exception, are packaged in class results returned FutureJoinTask, and did not throw again.

If you do not return results asynchronously, please do not use submitthe method

Conclusion first, I made a mistake, plain think submitand executethe difference is just a return to asynchronous result, a step does not return results, but the fact is cruel. In submit()the logic it must contain asynchronous tasks will be to catch the exception thrown, but because of improper use caused the exception is not thrown again.

Now ask a question ForkJoinPool#submit()in return ForkJoinTaskyou can get the results of asynchronous tasks, now that asynchronous exception is thrown, we try to get the results of the task will be how? We look directly at ForkJoinTask#get()the source.

public final V get() throws InterruptedException, ExecutionException {
    int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
        doJoin() : externalInterruptibleAwaitDone();
    Throwable ex;
    if ((s &= DONE_MASK) == CANCELLED)
        throw new CancellationException();
    //这里可以直接看到,异步任务出现异常会在调用get()获取结果的时候,会被包装成ExecutionException再次抛出
    if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
        throw new ExecutionException(ex);
    return getRawResult();
}
复制代码

Asynchronous tasks will be abnormal when calling get () to obtain the results, will be packaged into ExecutionExceptionthrown again, but an exception is where it is captured? Remain the same, all the threads of the threads have to be rewritten Thread#run()method, posted to ForkJoinPoolthe thread will be packaged into ForkJoinWorkerThread, so we look at the ForkJoinWorkerThread#run()implementation.

public void run() {
    if (workQueue.array == null) { // only run once
        Throwable exception = null;
        try {
            onStart();
            pool.runWorker(workQueue);
        } catch (Throwable ex) {
            //出现异常,捕获,再次抛出会在调用ForkJoinTask#get()的时候
            exception = ex;
        } finally {
            try {
                onTermination(exception);
            } catch (Throwable ex) {
                if (exception == null)
                    exception = ex;
            } finally {
                pool.deregisterWorker(this, exception);
            }
        }
    }
}
复制代码

The above analysis is based ForkJoinPool, is not all of the thread pool submitand executerealization are like this, we often use the thread pool ThreadPoolThreadto achieve what will be, the same ideas, we need to find delivered to ThreadPoolThreadasynchronous tasks will ultimately be packaged which is Threada sub-class or implement java.lang.Runnable#run, the answer isjava.util.concurrent.FutureTask

 public void run() {
      ...
        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);
            }
        } 
     ....
    }

复制代码

to sum up

java.util.concurrent.ExecutorService#submit(java.lang.Runnable)Why there is such a thread pool setting, in fact, our thinking should not be limited to the thread pool, but on acquiring asynchronous task results, whether it is abnormal result is an asynchronous , FutureTaskconcurrency tools as JDK provided, We have been given a very good answer, that get results asynchronous tasks, also belonging to the asynchronous abnormal result, abnormal, then the task of getting the result, the exception will be repackaged if running asynchronous tasks appear throws

Author: plz call me red scarf

Source: juejin.im/post/5d15c4...

Welcome to reprint this blog, but without the author's consent declared by this section must be retained, and given the original connection in the apparent position of the article page, otherwise the right to pursue legal responsibilities. Codeword is not easy, praise your point of my writing is the greatest force

Guess you like

Origin juejin.im/post/5d15c430f265da1bab29c1fe