栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

phaser替换countdownlatch

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

phaser替换countdownlatch

countdownlatch

countdownlatch是我们常用的同步类。但是在使用过程中有一个问题,就是他需要确定同步的次数。当我们的次数有变化的时候,就会对修改带来一定的问题。新增或者减少一个同步任务,只要次数没有跟着改变就会出现运行的问题。

  1. 新增了任务,会发现同步时数据不准确。同步线程比预期快运行。
  2. 减少任务,会发现线程一直等待,无法运行下去。

针对这种场景,我们常见的一种解决方法是维护一个数组,数组里是任务,countdownlatch的数量限制从数组获取,创建的任务也从数组获取。这样通过约定相同的数据源。满足变更的需要。这样就有一个地方是需要注意的。就是每个task里的countdownlatch是需要额外设置的。刚开始的时候countdownlatch也无法确认有多少的任务。所以经常看到的写法的样例如下。
首选构造一个可以填充countDownLatch的Runnable子类。

    class Task implements Runnable {
 CountDownLatch countDownLatch;

 public void setCountDownLatch(CountDownLatch countDownLatch) {
     this.countDownLatch = countDownLatch;
 }

 @Override
 public void run() {
     try {
  System.out.println("over");
     } finally {
  countDownLatch.countDown();
     }
 }
    }

然后就是创建操作的流程了

 Task[] runnables = new Task[]{new Task()};
 CountDownLatch countDownLatch =new CountDownLatch(runnables.length);
 for (Task runnable : runnables) {
     runnable.setCountDownLatch(countDownLatch);
     executorService.submit(runnable);
 }
 countDownLatch.await();

这样就做到了只添加任务,不需要管理其他的部分了。但是这也有一个问题。对java开发不友好。当task处理的任务没有相似性的时候,似乎lambda会带来更多的方便。lambda的操作还是比较单一,无法与上面的情况互相配合,lambda的时候就必须确定countDownLatch的个数了,所以无法把lambda表达式写到task数组里去。那是不是有方法可以动态的确定任务个数呢。phaser可以做到。

phaser

phaser的写法和countDownLatch类似,不过他自己又了维护增加和减少的方法。在每个task里,需要自己做增加和减少的操作。

 Phaser phaser = new Phaser();
 phaser.register();
 executorService.submit(() -> {
     try {
  Thread.sleep(3000);
  System.out.println("hello");
     } catch (InterruptedException e) {
  e.printStackTrace();
     } finally {
  phaser.arrive();
     }
 });
 phaser.register();
 phaser.arriveAndAwaitAdvance();

上面的demo中。
phaser.register();调用了2次。这两次的含义是不一样的。
第一次的是为了submit提交,他对应的是线程里的phaser.arrive();
第二次的是为了主线程阻塞同步, 利用phaser.arriveAndAwaitAdvance();进行同步操作,所以先自己做个增加。
看到这里或许有个疑问,就是为什么第一次的register不放在线程池内执行。
phaser本身判定的是次数是否为0。如果线程池进行了排队。那么线程的内容就无法被执行。register久久不能触发。
这样就会导致主线程自己做了增减,完成了判定为0的情况。
countDownLatch的一些问题phaser也有。就是线程池的拒绝策略触发时,线程内容无法被执行,所以无法触发减数操作,他们都会一直等待下去。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号