程序员面试经验
我正在测试以各种方式在Java列表中搜索低值和高值的方法,我意识到使用stream()和parallelStream()方法的结果要慢且性能差,而不仅仅是遍历列表…
这可能吗?
这怎么可能?
这是我的代码:
迭代整个数组:
private HighLowTuple calculateIteratingWholeArray( List<Integer> arrayWithNumbers, int from, int to ) { // long start = System.currentTimeMillis(); HighLowTuple result = new HighLowTuple( -1, Integer.MAX_VALUE ); for( int i = from; i < to; i++ ) { int value = arrayWithNumbers.get( i ); if( value > result.high ) { result.high = value; } if( value < result.low ) { result.low = value; } } // long end = System.currentTimeMillis(); // System.out.println( "duration internal calculateIteratingWholeArray from " + from + // " to + " + to + " " // + ( end - start ) + " ms" ); return result; }
这是使用Java 8流的代码:
private HighLowTuple calculateUsingStreamParallel( List<Integer> arrayWithIntegers ) { HighLowTuple result = new HighLowTuple( -1, Integer.MAX_VALUE ); Consumer<Integer> highlow = new Consumer<Integer>() { @Override public void accept( Integer number ) { if( result.high < number ) result.high = number; if( result.low > number ) result.low = number; } }; arrayWithIntegers.stream().parallel().forEach( highlow ); return result; }
参考方案
在开始考虑性能之前,您应该考虑正确性。您正在将并行流与非线程安全的自定义有状态Consumer
一起使用:
if( result.high < number ) // if another thread updates ⟨high⟩ right at this point you might loose a value result.high = number; if( result.low > number ) // again, possible loss of values here result.low = number;
此外,除非您将变量HighLowTuple.high
和HighLowTuple.low
声明为volatile
,否则当您使用多线程而不同步时,JVM的优化可能会导致更多更新丢失。但是,如果已将它们声明为volatile
,则对于性能降低(尽管仍具有错误的代码)应该不会感到惊讶。
解决方案是首先了解API。您已经重新发明了轮子,因为在Java 8中已经存在一种简单的方法来查找高低位:
IntSummaryStatistics s = arrayWithIntegers.stream() .parallel().mapToInt(Integer::intValue).summaryStatistics(); // if you still like your tuple class: return new HighLowTuple(s.getMax(), s.getMin());
但是,当然,如果您有一个int
值数组,则使用其中的IntStream
而不是绕开Collection
的Integer
效率会更高:
IntSummaryStatistics s = IntStream.of(array).parallel().summaryStatistics();
在Java Swing中输入JButton的键焦点? – java
如何在Java Swing中使JButton的Enter键成为焦点?我已经这样做了btn_Login.registerKeyboardAction(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("enter key pre…
在Java 8中,为什么ArrayList的默认容量现在为零? – java
我记得,在Java 8之前,ArrayList的默认容量为10。出乎意料的是,对默认(无效)构造函数的评论仍然显示:Constructs an empty list with an initial capacity of ten.来自ArrayList.java:/** * Shared empty array instance used for defau…
在Java 8流中,如何过滤掉不是枚举有效值的字符串? – java
我有一个枚举,我称之为对我的应用程序重要的安全权限的Permission。在数据库中,用户可能具有与我的应用程序无关的其他权限。从数据库中读取用户时,我得到一个List<String>,并且我想建立一个List<Permission>,而忽略了那些不是枚举值的字符串。public enum Permission { ADMIN, US…
Java:线程池如何将线程映射到可运行对象 – java
试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …
JAVA:字节码和二进制有什么区别? – java
java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…