产业气象站|并行流ParallelStream中隐藏的陷阱( 二 )


Lambda/Stream其实并不是天然线程安全的 , 线程安全的前提是它们本身被线程封闭调用 , 并且不引入多线程环境 , 像使用了并行流 , 本质就是引入了多线程环境 。 所以 , 在开发功能的时候 , 需要仔细思考一下:
是否真的有必要使用Lambda和流式编程?是否真的有必要用到并行流?如果使用了并行流 , 是否需要考虑引入额外的同步机制 , 例如锁?如果引入了额外的同步机制 , 是否考虑是强行使用并行流 , 违反了并行流设计的初衷?其实并发并不能提高性能 , 只能提高吞吐量 , 应该着重去发现和优化性能瓶颈 , 而不是拼命地把上游改造成并发调用 。?
笔者有代码洁癖 , 当时还发现了上面的代码存在映射操作 , 正确来说应该使用map()函数 , 而不是forEach()去遍历元素重新装进去另一个列表 , 方法中的逻辑体现了原开发者其实对Lambda一知半解 。
?
小结回到最初那个问题 , 其实使用并行流也可以保证执行结果和预期一致 , 不过一定需要引入额外的同步机制 , 例如这里使用「监视器」进行同步:
publicclassParallelStreamMain{publicstaticvoidmain(String[]args)throwsException{List&ltList&gtarray=newArrayList&lt&gt()Listitem1=newArrayList&lt&gt()Listitem2=newArrayList&lt&gt()Listtarget=newArrayList&lt&gt(100)array.add(item1)array.add(item2)finalObjectmonitor=newObject()array.parallelStream().forEach(x-&gt{synchronized(monitor){for(inti=0i&lt100000i++){target.add(i)}}})System.out.println(target.size())}}
上面的方法无论执行多少次 , 最终都只会输出:200000 。 这里在并行流中添加同步代码块的逻辑看起来确实比较滑稽 , 仅仅是为了说明如果在多线程环境下 , 对一个容器进行元素增加或者修改 , 只有添加额外的同步机制 , 才能保证最终的结果是符合预期的 。 ParallelStream是一个十分优秀的设计 , 但是需要考量其适用的场景 , 避免踏进自己为自己埋下的并发陷阱 。