本文来源于一次工作中,对某第三方平台进行二次开发。这个第三方平台提供的接口有一个很扯淡的限制:限制每秒调用频率为最多2次。解决这个问题,有下面几个问题需要解决:

  • 第三方调用频率策略修改,能快速修改,适应其策略
  • 在具体的业务逻辑不需要关注调用频率的变化

由此,想到使用自定义线程池来解决,调用时候,只需要忘线程池提交任务。其他接口调用频率交给线程池来处理。我使用单线程池,同时修改等待队列为DelayQueue,DelayQueue支持延迟固定时间take一个元素。

 1     public E take() throws InterruptedException {
 2         final ReentrantLock lock = this.lock;
 3         lock.lockInterruptibly();
 4         try {
 5             for (;;) {
 6                 E first = q.peek();
 7                 if (first == null)
 8                     available.await();
 9                 else {
10                     long delay = first.getDelay(NANOSECONDS);
11                     if (delay <= 0)
12                         return q.poll();
13                     first = null; // don't retain ref while waiting
14                     if (leader != null)
15                         available.await();
16                     else {
17                         Thread thisThread = Thread.currentThread();
18                         leader = thisThread;
19                         try {
20                             available.awaitNanos(delay);
21                         } finally {
22                             if (leader == thisThread)
23                                 leader = null;
24                         }
25                     }
26                 }
27             }
28         } finally {
29             if (leader == null && q.peek() != null)
30                 available.signal();
31             lock.unlock();
32         }
33     }

DelayQueue的take方法

其中有最关键的是:

1  long delay = first.getDelay(NANOSECONDS);
2                     if (delay <= 0)
3                         return q.poll();

View Code

所以最为关键的试试实现自定义的getDelay方法。由于该对列只支持Delay类型,而普通的线程提交只支持Runnable和Callble,需要做一个适配。

 1 public class DelayedThreadPoolFactoryBean extends ThreadPoolExecutorFactoryBean {
 2     Logger logger = LoggerFactory.getLogger(this.getClass());
 3     private TimeUnit timeUnit;
 4     private long delayed;
 5
 6     public void setTimeUnit(TimeUnit timeUnit) {
 7         this.timeUnit = timeUnit;
 8     }
 9
10     public void setDelayed(long delayed) {
11         this.delayed = delayed;
12     }
13     @Override
14     protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
15         return new DelegateDelayedQueue();
16     }
17
18     @Override
19     protected ThreadPoolExecutor createExecutor(int corePoolSize,int maxPoolSize,int keepAliveSeconds,final BlockingQueue<Runnable> queue,ThreadFactory threadFactory,RejectedExecutionHandler rejectedExecutionHandler) {
20
21         return new ThreadPoolExecutor(corePoolSize, maxPoolSize,
22                 keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler){
23             @Override
24             public void execute(Runnable command) {
25                 final DelegateDelayedQueue queue1 = (DelegateDelayedQueue)queue;
26                 DelegateDelaye delegateDelaye = new DelegateDelaye(command,queue1,timeUnit,delayed);
27                 super.execute(delegateDelaye);
28             }
29         };
30     }
31     private class DelegateDelaye implements Delayed,Runnable{
32         private Runnable runnable;
33         private DelegateDelayedQueue delegateDelayedQueue;
34         private TimeUnit timeUnit;
35         private long delayed;
36         public DelegateDelaye(Runnable runnable,DelegateDelayedQueue delegateDelayedQueue,TimeUnit unit,long delayed){
37             this.runnable = runnable;
38             this.delegateDelayedQueue = delegateDelayedQueue;
39             this.timeUnit = timeUnit;
40             this.delayed = delayed;
41         }
42
43         @Override
44         public long getDelay(TimeUnit unit) {
45             if(delegateDelayedQueue.getLast() == 0){
46                 return -1;
47             }
48             return unit.convert(delegateDelayedQueue.getLast() +
49                     TimeUnit.MILLISECONDS.convert(5,TimeUnit.SECONDS) -
50                     System.currentTimeMillis(),TimeUnit.MILLISECONDS);
51         }
52
53         @Override
54         public int compareTo(Delayed o) {
55             return 0;
56         }
57
58         @Override
59         public void run() {
60             runnable.run();
61         }
62     }
63     private class DelegateDelayedQueue extends DelayQueue{
64         private long last = 0;//默认为0
65
66         @Override
67         public Delayed poll() {
68             Delayed delayed =  super.poll();
69             if(delayed != null){
70                 this.last = System.currentTimeMillis();
71             }
72             return delayed;
73         }
74
75         @Override
76         public Delayed take() throws InterruptedException {
77             Delayed delayed =  super.take();
78             if(delayed != null){
79                 this.last = System.currentTimeMillis();
80             }
81             return delayed;
82         }
83
84         @Override
85         public Delayed poll(long timeout,TimeUnit unit) throws InterruptedException {
86             Delayed delayed = super.poll(timeout,unit);
87             if(delayed != null){
88                 this.last = System.currentTimeMillis();
89             }
90             return delayed;
91         }
92
93         public long getLast() {
94             return last;
95         }
96     }
97 }

完整实现的线程池

简单测试:

 1 @Test
 2     public void testSinglePool(){
 3         ExecutorService executorService = executoryServiceFactory.executorService(ExecutoryServiceFactory.Pool.DELAYED);
 4
 5         executorService.submit(new Callable<String>() {
 6            @Override
 7            public String call() throws Exception {
 8                System.out.println(TimeUnit.SECONDS.convert(System.currentTimeMillis(),TimeUnit.MILLISECONDS));
 9                return null;
10            }
11        });
12         executorService.execute(new Runnable() {
13             @Override
14             public void run() {
15                 System.out.println(TimeUnit.SECONDS.convert(System.currentTimeMillis(),TimeUnit.MILLISECONDS));
16             }
17         });
18         executorService.execute(new Runnable() {
19             @Override
20             public void run() {
21                 System.out.println(TimeUnit.SECONDS.convert(System.currentTimeMillis(),TimeUnit.MILLISECONDS));
22             }
23         });
24         executorService.execute(new Runnable() {
25             @Override
26             public void run() {
27                 System.out.println(TimeUnit.SECONDS.convert(System.currentTimeMillis(),TimeUnit.MILLISECONDS));
28             }
29         });
30         executorService.execute(new Runnable() {
31             @Override
32             public void run() {
33                 System.out.println(TimeUnit.SECONDS.convert(System.currentTimeMillis(),TimeUnit.MILLISECONDS));
34             }
35         });
36         executorService.shutdown();
37         try {
38             executorService.awaitTermination(5,TimeUnit.MINUTES);
39         } catch (Exception e){}
40     }

View Code

结果符合预期的效果,固定频率执行任务。

转载于:https://www.cnblogs.com/dragonfei/p/5908900.html

固定频率调用接口方案相关推荐

  1. Oracle调用接口(OCI)源码剖析(2):执行SQL语句并获取结果

    概述 接着上一篇文章<Oracle调用接口(OCI)源码剖析(1):创建数据库连接>,我们继续对OCI中执行SQL语句并获取结果的源码进行剖析.该操作主要是由两个函数完成的:CDbExec ...

  2. navision系统和sap区别_SAP那些事-实战篇-89-浅谈金税接口方案

    以前金税接口这块一直是销售顾问在做,虽然和财务相关,也没有怎么关注.这次项目把金税接口分到了财务模块,结果遇到了一些问题,趁此机会把这块总结一下方案,供各位看官参考. 方案1: 文本方案,这个方案最早 ...

  3. PHP微信防止token过期,微信调用接口,防止Access_token过期的方法

    大家都知道,微信中调用订阅用户接口中需要Access_token,而根据微信官方文档中说明: access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.正常情 ...

  4. android 播放固定频率的声音,Android 播放指定频率正弦波声音

    用Android设备来播放指定频率的纯音,首先考虑到纯音是一种固定频率的声波,其实也就是正弦声波了.其实所有声音都是有正弦波组成,只不过纯音是固定频率的正弦波.那么要实现Andoird播放纯音,那么首 ...

  5. 演示淘宝API调用接口

    很简单,新建一个工程,拖一个IDHttp,Button和Memo到窗体上去 然后在这个Button的OnClick事件中写入如下代码:[delphi] view plaincopyprocedureT ...

  6. android 播放固定频率的声音,Android 播放指定频率的纯音

    用Android设备来播放指定频率的纯音,首先考虑到纯音是一种固定频率的声波,其实也就是正弦声波了.其实所有声音都是有正弦波组成,只不过纯音是固定频率的正弦波.那么要实现Andoird播放纯音,那么首 ...

  7. 两个系统如何调用接口获取返回值

    1.使用场景 两个公司进行合作,但是是两个毫不相关的项目,所以就需要使用http请求远程访问接口获取返回值. 2.如何做到 使用http请求建立连接访问接口获取返回值并解析 调用其他系统接口工具类如下 ...

  8. java调用php接口_java 如何调用接口

    在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适,所以,问题来了,java如何调用接口?很多项目都会封装规定好本身项目的接口规范,所以大多数需要去调用对方提供的接口或第三方接 ...

  9. java调用接口失败重调_接口调用失败的退避策略

    退避策略简介 在开发过程中我们经常会遇到调用接口失败的情况.遇到这种情况,我们有时候需要重试机制,常用的重试(退避)策略有: 固定的时间间隔重试一次,最多重试N次:比如我现在一个接口调用失败了,不是立 ...

最新文章

  1. break与continue的的用法以及区别
  2. python怎么写中文至excel_Python 解决中文写入Excel时抛异常的问题
  3. Cannot open precompiled header file: 'Debug/***.pch': No such file or directory
  4. HarmonyOS 2.0:正式开源,年底面向开发者发布智能手机 Beta 版本
  5. windows服务与前台交互
  6. 广播接收者的特点和版本差异
  7. 银河麒麟系统10服务器安装教程,麒麟系统下安装win10的详细教程
  8. 战舰 Linux服务端,战舰帝国一键端手游服务端+GM工具+视频教程
  9. 《计算机科学与工程导论:基于IoT和机器人的可视化编程实践方法第2版》一2.1 工作流和可视化编程...
  10. 【后端学习之路】Browsers and how they work?
  11. 简述igp和egp_igp egp
  12. mysql字符串分割为数组_mysql下将分隔字符串转换为数组
  13. 一次Spring Cache使用不当带来的生产环境问题
  14. Riverbed SteelConnect荣获2017 Interop东京展“最佳展示奖”
  15. 面试要谈的计算机网络
  16. 工作四年,分享15个对Java 程序员有用的库
  17. 文件操作安全之-文件解析原理篇
  18. wp7开发实例:Baby Sign Language
  19. python 处理csv文件 一个简单的数据处理任务
  20. b ascll 对照表

热门文章

  1. 动态图制作软件设计(二)
  2. 【Vue】—计算属性
  3. 【Express】 —利用 Express 托管静态文件
  4. 数据库原理—数据、数据库(一)
  5. 中心极限与大数定理律的关系_多元函数的极限、连续性分析
  6. 请问用微信很少语音而且打字不喜欢打错别字的是什么样的人?能说明这样的人办事认真吗?
  7. 退休后能领到4000元以上的养老保险金处于什么水平呢?
  8. 早上起床后喝的第一杯水最好选择白开水
  9. 同为EA888发动机,迈腾和奥迪A4L,为何差价10万多?
  10. 发展前景好的互联网技术方面,你觉得比较适合女孩子的都有哪些啊?