参考并建议阅读《Java 8函数式编程》
转载请注明出处:http://blog.csdn.net/cuiods/article/details/53727191
如果将程序比作马拉车,那么并行可以看做试图用很多马拉同一辆车,以提高车速,而单纯的并发则是一匹马同时拉很多车,要做到每辆车兼顾且不翻车。处理很多马拉很多车的问题,可以看作是处理并行与并发的问题。在Java8函数式编程的支持下,如何处理并行与并发问题呢?
对于流操作,支持并行化只需要多调用一个方法parallelStream。
public int parallelArraySum() {
return albums.parallelStream()
.flatMap(Album::getTracks)
.mapToInt(Track::getLength)
.sum();
}
在知道这个方法之后,我们都会倾向于在所有的流方法后加上这个方法,以体现代码的“并行化”特征。然而,在实际运用中如果数据量较少(100?),使用该方法会严重降低效率,只有在处理大量数据时,该方法再能发挥出并行的优势。
使用蒙特卡洛模拟法并行化模拟掷骰子事件:
public Map parallelDiceRolls() {
double fraction = 1.0 / N;
return IntStream.range(0, N)
.parallel()
.mapToObj(twoDiceThrows())
.collect(groupingBy(side -> side,
summingDouble(n -> fraction)));
}
使用流的并行化方法确实可以大量减少代码行数。
调用流的并行方法有如下限制:
(1)Reduce方法的限制:Reduce的初始值必须是组合函数的恒等值。说人话就是初始值与其他值做reduce操作时,结果等于其他值。此外,reduce操作必须符合结合律。
(2)避免持有锁。流的并行方法会自行加锁,不要自找麻烦。
Java8引入了一些针对数组的并行化操作,这些方法添加在Arrays中。
比如,创建一个数组并初始化数组中的元素:
public static double[] parallelInitialize(int size) {
double[] values = new double[size];
Arrays.parallelSetAll(values, i -> i);
return values;
}
通常情况下,我们的应用程序是这样工作的:用户与服务器建立TCP连接,服务器调用方法向用户传输数据,这个方法会阻塞当前线程。这样的方法叫做阻塞式IO。阻塞式IO的缺点是当有大量用户时,用户会和服务器建立大量连接,扩展性不是很好。
非阻塞式IO,又叫异步IO,对于读写的调用立即返回,真正读写的操作在另一个线程完成,这样就可以同时执行其他任务。
首先介绍两款用于处理异步操作的框架:
vert.x:https://github.com/eclipse/vert.x
rxjava:https://github.com/ReactiveX/RxJava
使用Vert.x框架接收TCP连接的示例(类似于Servlet)
public class ChatVerticle extends Verticle {
public void start() {
vertx.createNetServer()
.connectHandler(socket -> {
container.logger().info("socket connected");
socket.dataHandler(new User(socket, this));
}).listen(10_000);
container.logger().info("ChatVerticle started");
}
}
为connectHandler输入一个lambda表达式,当有用户连接时会调用该表达式,这是一个回调。使用回调的好处是不需要手动管理线程,Vert.x自动帮助我们管理线程。
在Vert.x中,我们通过事件总线传递消息。
首先需要注册一个回调来写入消息,registerHandler方法将一个程序和一个地址相关联,有消息发给该地址时,就将之作为参数传递给处理程序。
eventBus.registerHandler(user, (Message msg) -> {
sendClient(msg.body());
});
eventBus是Vert.x的事件总线,它允许在verticle对象之间以非阻塞式IO的方式传递消息。
当想把消息发送给某一个用户时,可以使用代表那个用户的地址发送消息。
eventBus.send(user, name.get() +‘ >’ + message);
使用publish方法可以实现群发功能。
private void broadcastMessage(String message) {
String name = this.name.get();
eventBus.publish(name + ".followers", name +‘ >’ + message);
}
verticle对象向事件总线发送消息通信,不需要添加锁或synchronized关键字。
对于并发问题,我现在并没有解决这类问题的实际经验,因此还不能完全理解java对这类问题多出的支持,还是要继续提高姿势水平。
参考并建议阅读《Java 8函数式编程》