我正在测试以各种方式在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:字节码和二进制有什么区别? - javajava字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…