浅析java编程优势略举一二

一、java对流处理的封装非常便捷,一般情况一下,因为steam数据都是比较大,或者有规律的数据,这时候利用java便利的接口很容易实现

Stream和parallelStream选择
在从stream和parallelStream方法中进行选择时,我们可以考虑以下几个问题:

1.是否需要并行?

2.任务之间是否是独立的?是否会引起任何竞态条件?

3.结果是否取决于任务的调用顺序?

对于问题1,在回答这个问题之前,需要明确要解决的问题是什么,数据量有多大,计算的特点是什么?并不是所有的问题都适合使用并发程序来求解,比如当数据量不大时,顺序执行往往比并行执行更快。毕竟,准备线程池和其它相关资源也是需要时间的。但是,当任务涉及到I/O操作并且任务之间不互相依赖时,那么并行化就是一个不错的选择。通常而言,将这类程序并行化之后,执行速度会提升好几个等级。

对于问题2,如果任务之间是独立的,并且代码中不涉及到对同一个对象的某个状态或者某个变量的更新操作,那么就表明代码是可以被并行化的。

对于问题3,由于在并行环境中任务的执行顺序是不确定的,因此对于依赖于顺序的任务而言,并行化也许不能给出正确的结果。

二、java的并发处理多任务提供的类CompletableFuture,一是提高实现的功能代码性能,充分利用多核cpu的优势

CompletableFuture的优点是:

  • 异步任务结束时,会自动回调某个对象的方法
  • 异步任务出错时,会自动回调某个对象的方法
  • 主线程设置好回调后,不再关心异步任务的执行

常用方法

依赖关系

thenApply():把前面任务的执行结果,交给后面的Function
thenCompose():用来连接两个有依赖关系的任务,结果由第二个任务返回
and集合关系

thenCombine():合并任务,有返回值
thenAccepetBoth():两个任务执行完成后,将结果交给thenAccepetBoth处理,无返回值
runAfterBoth():两个任务都执行完成后,执行下一步操作(Runnable类型任务)
or聚合关系

applyToEither():两个任务哪个执行的快,就使用哪一个结果,有返回值
acceptEither():两个任务哪个执行的快,就消费哪一个结果,无返回值
runAfterEither():任意一个任务执行完成,进行下一步操作(Runnable类型任务)
并行执行

allOf():当所有给定的 CompletableFuture 完成时,返回一个新的 CompletableFuture
anyOf():当任何一个给定的CompletablFuture完成时,返回一个新的CompletableFuture
结果处理

whenComplete:当任务完成时,将使用结果(或 null)和此阶段的异常(或 null如果没有)执行给定操作
exceptionally:返回一个新的CompletableFuture,当前面的CompletableFuture完成时,它也完成,当它异常完成时,给定函数的异常触发这个CompletableFuture的完成
-----------------------------------
java默认线程池大小 java completefuture 默认线程池

三、对比一下parallelStream和CompletableFuture

class MyTask {
    private final int number;
    private final int duration;

    public MyTask(int number, int duration) {
        this.number = number;
        this.duration = duration;
    }

    public int calculate() {
        System.out.println(Thread.currentThread().getName());
        try {
            Thread.sleep(duration * 1000);
        } catch (final InterruptedException e) {
            throw new RuntimeException(e);
        }
        return number;
    }

    @Override
    public String toString() {
        return "MyTask{" +
                "number=" + number +
                ", duration=" + duration +
                '}';
    }
}
@Test
public void testParallel() {
    List<MyTask> taskList = IntStream.range(0, 10)
            .mapToObj(i -> new MyTask(i, 1))
            .collect(toList());
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    List<Integer> result = taskList.parallelStream()
            .map(MyTask::calculate)
            .collect(toList());
    System.out.printf("Processed %d tasks in %d millis\n", taskList.size(), stopWatch.getTime());
    System.out.println(result);
}
@Test
public void testCompletableFutureSupplyAsync() {
    List<MyTask> taskList = IntStream.range(0, 10)
            .mapToObj(i -> new MyTask(i, 1))
            .collect(toList());
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    List<Integer> result = taskList.stream()
            .map(item -> CompletableFuture.supplyAsync(item::calculate))
            .collect(toList()).stream().map(CompletableFuture::join)
            .collect(toList());
    //main线程
    System.out.printf("Processed task in %d millis\n", stopWatch.getTime());
    System.out.println(result);
}

测试结果:

10个任务总共耗时2015ms,parallelStream用的线程池是ForkJoinPool.commonPool(),从运行结果可以看出,用了7个ForkJoinPool线程和1个主线程。

CompletableFuture耗时2014ms,从耗时上看没有什么特殊的优势,但这一次用了7个ForkJoinPool线程(其中1、2、3号线程被复用),与parallelStream不同的是,主线程没有被用到。

CompletableFuture更加的灵活,我们可以配置其线程池的大小确保整体的计算不会因为等待I/O而发生阻塞,《Java并发编程实战》一书中给出的建议是:

如果要执行的任务是计算密集型的并且没有IO操作,推荐使用并行流parallelStream,因为实现简单效率也高,其使用的线程池ForkJoinPool.commonPool()设置的线程数默认为CPU数量-1,可最大化利用CPU,CPU密集型任务各个线程都很忙碌(运行状态),没有必要创建比核数更多的线程
如果要执行的任务涉及到网络I/O或磁盘I/O等耗时操作,使用CompletableFuture的灵活性更好,因为大部分线程处于等待状态,需要将它们利用起来,让它们更加忙碌,并且在逻辑中加入异常处理可以更有效的监控是什么原因触发了等待。

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值