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 parallelStream
parallel flow is a good thing, because the daily development stream
more 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 submit
method and will not print the error log, use execute
the method to print out the error log, but to submit
return to the FutureJoinTask
calling 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 submit
to 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 submit
the method
Conclusion first, I made a mistake, plain think submit
and execute
the 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 ForkJoinTask
you 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 ExecutionException
thrown 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 ForkJoinPool
the 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 submit
and execute
realization are like this, we often use the thread pool ThreadPoolThread
to achieve what will be, the same ideas, we need to find delivered to ThreadPoolThread
asynchronous tasks will ultimately be packaged which is Thread
a 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 , FutureTask
concurrency 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