1.测试进程与测试结果
package com.example.demo.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
/**
* <p>
* Description: TODO
* </p>
*
* @author majun
* @version 1.0
* @date 2021-05-20 22:14
*/
public class Test{
private static Logger log=LoggerFactory.getLogger(Test.class);
public static void main(String[] args) {
List<Integer> ids = Arrays.asList(1, 2);
ids.parallelStream().forEach(integer -> {
log.info(integer+"start");
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info(integer+"end");
throw new RuntimeException(integer+"异常了");
});
log.info("xxx");
}
}
多次运行可以发现有两种异常输出
情况1:
- main线程输出:2start
- ForkJoin线程输出:1start
- main线程先抛出异常:2异常了,这时ForkJoin线程随着main线程异常而终止了因为没有输出1end及其抛出的异常
- 最终由main线程输出了异常信息:Exception in thread "main" java.lang.RuntimeException: 2异常了
22:20:16.294 [main] INFO com.example.demo.util.Test - 2start
22:20:16.317 [ForkJoinPool.commonPool-worker-1] INFO com.example.demo.util.Test - 1start
Exception in thread "main" java.lang.RuntimeException: 2异常了
at com.example.demo.util.Test.lambda$main$0(Test.java:32)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:401)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:734)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:583)
at com.example.demo.util.Test.main(Test.java:24)
22:20:16.988 [main] INFO com.example.demo.util.Test - 2endProcess finished with exit code 1
情况2:
- main线程输出:2start
- ForkJoin线程输出:1start
- ForkJoin线程输出:1end
- main线程输出:2end
- 最终由main线程输出了异常信息:Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: 1异常了
22:22:15.954 [main] INFO com.example.demo.util.Test - 2start
22:22:15.954 [ForkJoinPool.commonPool-worker-1] INFO com.example.demo.util.Test - 1start
22:22:16.561 [ForkJoinPool.commonPool-worker-1] INFO com.example.demo.util.Test - 1end
22:22:16.658 [main] INFO com.example.demo.util.Test - 2end
Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: 1异常了
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:583)
at com.example.demo.util.Test.main(Test.java:24)
Caused by: java.lang.RuntimeException: 1异常了
at com.example.demo.util.Test.lambda$main$0(Test.java:32)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)Process finished with exit code 1
2.结论
- parallelStream不同于普通stream,它是多线程并行执行的,涉及线程安全问题的业务慎用
- parallelStream 并行执行的第一个进程为main进程,随后执行的是根据main进程fork的进程
- 如果main进程率先抛出异常,则其它fork进程会立即终止,最终抛出main进程的那个异常
- 如果是fork进程率先抛出异常,则其它进程还会继续进行,虽然其它进程虽然还继续运行,但是最终抛出的异常仍是最先fork进程抛出的异常,但是由main进程帮fork进程抛出来的,如上的情况2就是这种,可以看到这里的异常信息比较长,main线程异常信息包括了fork进程的异常类型“java.lang.RuntimeExcetion”及异常信息“1异常了”。