- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有以下异常(堆栈跟踪):
java.lang.NullPointerException
at sun.reflect.GeneratedConstructorAccessor171.newInstance(Unknown Source) ~[?:?]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:1.8.0_40]
at java.lang.reflect.Constructor.newInstance(Constructor.java:422) ~[?:1.8.0_40]
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:598) ~[?:1.8.0_40]
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677) ~[?:1.8.0_40]
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735) ~[?:1.8.0_40]
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160) ~[?:1.8.0_40]
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:174) ~[?:1.8.0_40]
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233) ~[?:1.8.0_40]
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) ~[?:1.8.0_40]
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:583) ~[?:1.8.0_40]
at com.tradair.tnet.services.trades.TradeService.updateUnrealizedPNL(TradeService.java:173) ~[tnet.jar:5.1.1.0-SNAPSHOT]
从我的 TradeService
类开始:
public void updateUnrealizedPNL(Set<Org> orgsToCaluclate, Set<Org> orgsToSendUpdate) {
orgsToCaluclate.parallelStream().forEach(o -> {
pnlService.updateMidPrices(o);
Collection<SystemTradeOrder> allLiveTradesByOrgId = tradesRepository.getAllLiveTradesByOrgId(o.getId());
updateUnrealizedPNL(o, allLiveTradesByOrgId);
});
// more code ....
所以看起来异常是在运行 forEach(..)
方法时在 java native 代码中抛出的。我的意思是,NullPointerException
不是从我自己的代码中抛出的 - 不是从作为参数出现在 forEach(..)
方法中的我的消费者函数中抛出的。
我仔细检查了这段代码运行时没有对 orgsToCaluclate
集进行修改。
这是 orgsToCaluclate
的初始化:
Set<Org> orgsToCaluclate = getMarginOrgs();
orgsToCaluclate = orgsToCaluclate.stream()
.filter(org -> !isOrgInCloseout(org.getId())).collect(Collectors.toSet());
有什么想法吗?..
最佳答案
我们习惯说异常的堆栈跟踪反射(reflect)了“它发生的地方”,但这是一个不精确的说法。异常的堆栈跟踪通常反射(reflect)了它的实例是在哪里创建的。
当我们有表单的代码时,
1 String s=null;
2 s.length();
当我们尝试取消引用 null
以调用方法 length()
时,JRE 将创建一个 NullPointerException
实例,因此它的堆栈跟踪将报告第 2
行。
但是,当我们有如下代码时
1 String s=null;
2 if(s == null) {
3 RuntimeException rt=new NullPointerException();
4 throw rt;
5 }
堆栈跟踪不会报告在何处检测到错误条件(第 2
行)或在何处抛出异常(第 4
行),但会报告实例在何处发生已在 3
行中创建。
对于大多数实际情况,这些地方足够接近,不会产生显着差异,但在这里,我们有一个特殊的情况。
作为tonakai has pointed out , ForkJoinTask
将通过反射创建一个已经遇到的异常的新实例,如我们所见in its source code当线程不匹配时。
当它成功时,它的堆栈跟踪将准确地反射(reflect)新异常实例的创建位置,这是在一些执行反射实例创建的生成代码中。当然,这种成功的创建与JRE在执行相同代码时由于错误条件而创建异常的情况无法区分。
但是当我们仔细观察 source code ,我们看到整个反射创作都包含在
584 try {
…
604 } catch (Exception ignore) {
605 }
阻止。所以如果操作真的失败了,看不出有什么异常。相反,代码已经失败以返回原始异常。这表明反射代码没有失败,而是我们看到成功地反射创建的 NullPointerException
实例由 getThrowableException()
返回,后来被 故意抛出ForkJoinTask
报告在处理过程中另一个线程中有一个 NullPointerException
。
但是这段代码将新异常的原因初始化为指向原始异常。例如。以下代码:
import java.util.stream.IntStream;
public class Main
{
public static void main(String[] args) {
Thread main=Thread.currentThread();
IntStream.range(0, 1000).parallel().forEach(i -> {
if(Thread.currentThread()!=main)
throw new NullPointerException();
});
}
}
打印
Exception in thread "main" java.lang.NullPointerException
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:598)
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$OfInt.evaluateParallel(ForEachOps.java:189)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.IntPipeline.forEach(IntPipeline.java:404)
at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:560)
at Main.main(Main.java:7)
Caused by: java.lang.NullPointerException
at Main.lambda$main$0(Main.java:9)
at java.util.stream.ForEachOps$ForEachOp$OfInt.accept(ForEachOps.java:205)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
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)
所以你仍然能够认出发生了什么。您只需要注意原因。由于您问题中的堆栈跟踪看起来不像典型的 Throwable.printStackTrace()
输出,它可能是生成此输出的代码忽略了异常的原因属性。
作为附录,我们可以使用自定义异常类型检查如果重新创建真的失败会发生什么:
import java.util.stream.IntStream;
public class Main
{
public static class CustomException extends RuntimeException {
public CustomException() {
System.err.println("will deliberately fail");
throw new NullPointerException();
}
private CustomException(String message) {
super(message);
}
}
public static void main(String[] args) {
Thread main=Thread.currentThread();
IntStream.range(0, 1000).parallel().forEach(i -> {
if(Thread.currentThread()!=main)
throw new CustomException("forced failure");
});
}
}
将打印
will deliberately fail
Exception in thread "main" Main$CustomException: forced failure
at Main.lambda$main$0(Main.java:18)
at java.util.stream.ForEachOps$ForEachOp$OfInt.accept(ForEachOps.java:205)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
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)
表明在反射重建期间通过默认构造函数抛出的 NullPointerException
未报告,而是直接抛出来自其他线程的原始异常。
关于java - 执行 parallelStream.forEach(..) 时 native java 代码中的 NullPointerException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38994907/
这个问题已经有答案了: How do I write a correct micro-benchmark in Java? (11 个回答) 已关闭 5 年前。 我正在对 Java 聚合操作进行一些性
我发现我对并行流提供的一致性保证略有挣扎: 1. myList.parallelStream().map(mymapper).forEach(myFn) 2. // Is myFn guarantee
我有一个方法可以并行计算列表中数字的平方并将它们相加: public static double sumSquared(List values) { return values
这个问题已经有答案了: How do Java 8 parallel streams behave on a thrown exception? (1 个回答) 已关闭 4 年前。 我正在研究java
通常当使用 Java 8 的 parallelStream() 时,结果是通过默认的、通用的 fork-join 池(即 ForkJoinPool.commonPool())执行。 这显然是不可取的,
Java 8 parallelStream 似乎使用了比系统属性 java.util.concurrent.ForkJoinPool.common.parallelism 指定的线程更多的线程。这些单
我有以下代码,有时它的行为不确定。例如,我在那里传递了 3 个事件,而输出只有两个!你能解释一下这种行为的原因吗? public List getEventResponse(final List ev
Java8并行流(parallelStream)注意点 在最初使用并行流的时候,查询列表会偶尔性报空指针异常,这令我非常纳闷 代码是这样的: ?
使用示例可能更容易解释我想要做的事情。假设我必须遵循两个数组: int firstArray[] = {1, 2, 3, 4, 5}; int secArray[] = {1, 2, 3, 4, 5}
我正在尝试使用 chronicleMap.parallelStream: myChronicleMap.entrySet().parallelStream().forEach((entry) -> {
我正在使用parallelStream并行上传一些文件,有些是大文件,有些是小文件。我注意到并非所有 worker 都被使用。 一开始一切都运行良好,所有线程都被使用(我将并行度选项设置为 16)。然
这个问题在这里已经有了答案: How can I turn a List of Lists into a List in Java 8? (12 个答案) 关闭 8 年前。 我想将并行流中的列表结果
我有以下代码 public void addNames(){ List names = new ArrayList names.parallelStream().foreach(name-
如果输入大小太小,库 automatically serializes the execution of the maps in the stream ,但这种自动化没有也不能考虑 map 操作的繁重
我创建了一个并行度为 25 的自定义 ForkJoinPool。 customForkJoinPool = new ForkJoinPool(25); 我有一个包含 700 个文件名的列表,我使用这样
我在 Internet 上看到了很多示例,为了使用流 API 来执行并行操作,只需像这样调用 .parallelStream() 方法: mySet .parallelStream()
考虑这个(完全人为的)Java 代码: final List s = Arrays.asList(1, 2, 3); final int[] a = new int[1]; a[0] = 100; s
谁能告诉我为什么会这样,这是预期的行为还是错误 List a = Arrays.asList(1,1,3,3); a.parallelStream().filter(Objects::nonNull)
方法一 通常,非常快,并且效果很好。 public static int loops = 500; private static ExecutorService customPool = Execut
默认情况下,parallelStream 内的 commonPool 大小应为 cpu_cores - 1。 但是,在我的应用程序中,它始终大于硬件 cpu_cores。 VisualVM 截图: 很
我是一名优秀的程序员,十分优秀!