JAVA实现节流阀在前端开发中,有种效果叫做节流阀

顾名思义,节流阀的作用是限制某些事件的执行频率,基本代码如下:

obj.event=function(){clearTimeout(obj.timer);obj.timer=setTimeout(()=>{execute},timeout);}JAVA实现

在JAVA中,我们也需要一些类似的效果

抽象

我们抽象出一个pool,这个pool可以接受你的任务,如果是同一个任务,会覆盖之前还没执行的任务

classPool{voidexecute(Stringkey,Runnablerunnable,longdelay){}}

这里的key就代表你的任务,delay就是任务的间隔时间

使用线程池

我们可以引入线程池来简化编码

privateScheduledExecutorServicescheduledExecutorService=Executors.newScheduledThreadPool(6);

线程池的作用是进行任务调度,ScheduledExecutorService允许我们提交一个延迟执行的任务

思路

当程序员提交一个任务,pool会判断这个任务是否在pool中待执行,
如果是待执行,则取消pool中的任务,后用新提交的这个任务替代它

scheduledExecutorService提交任务会返回一个future,在执行之前,我们可以取消它

完整代码如下

voidexecute(Stringkey,Runnablerunnable,longdelay){ScheduledFuture<?>task=map.get(key);if(task!=null){task.cancel(false);}ScheduledFuture<?>schedule=scheduledExecutorService.schedule(()->{runnable.run();map.remove(key);},delay,TimeUnit.MILLISECONDS);map.put(key,schedule);}

这里使用了一个map来记住任务的执行情况

测试第一个测试

//应该只会输出一个2List<Integer>list=newArrayList<>();CountDownLatchlatch=newCountDownLatch(1);Poolpool=newPool();for(inti=0;i<3;i++){intfinalI=i;pool.execute("task",()->{System.out.println(finalI);list.add(finalI);latch.countDown();},1000);Thread.sleep(800);}latch.await();assertEquals(1,list.size());assertEquals(2,list.get(0));

这里依次执行三次任务,但是这个任务的延迟时间是1000,任务执行的间隔是800

间隔比延迟实现还要小,所以前面2个任务会被忽略,结果只会输出2

第二个测试

//应该输出012List<Integer>list=newArrayList<>();CountDownLatchlatch=newCountDownLatch(3);Poolpool=newPool();for(inti=0;i<3;i++){intfinalI=i;pool.execute("task",()->{System.out.println(finalI);list.add(finalI);latch.countDown();},1000);Thread.sleep(1100);}latch.await();assertEquals(3,list.size());assertEquals(3,list.size());

这个测试任务间隔比延迟还要大,所以三个任务会被依次执行

输出 0 1 2


作者:0xcaffebabe
链接:https://www.imooc.com/article/305039
转自来源:慕课网