问题
最近研究比特币, 从网络上下载区块的时候有时候碰到一个问题: 比特币的网络的请求和响应式是异步, 发送了一个请求无法判断这个请求有没有响应, 为了解决这个问题, 使用超时机制. 如果一起请求发起后, 一段时间没有接受到响应, 就切换到另外一个服务器重新请求, 于是就实现了一个工具类 TimeoutTaskManager
实现说明
通过一个死循环的线程while (true) { ... }
来监听超时, 如果超时则切换到下一个服务器, 如果该线程被中断会直接退出
执行过程
假如有一个任务(Consumer<T> consumer
), 有N台服务器可以支持(public void addProvider(T provider) {
), 当前正在执行的服务如果出现超时的时候(int time, TimeUnit unit
), 自动按照队列(Queue<T> queue
) 顺序尝试, 如果队列里面没有支持者则会一直等待 (waiting.await();
), 直到 addProvider(T provider)
的时候 waiting.signal()
唤醒.
- 构造函数指定 任务和超时时间
public TimeoutTaskManager(Consumer<T> consumer, int time, TimeUnit unit) { ... }
- 添加服务的提供者
public void addProvider(T provider) { ... }
- 移除提供者
public synchronized void remove(T e) { ... }
- 如果是指定的任务是 几个任务的合集, 例如:集合中的任务耗时不同, 可以在完成一个任务后重置任务的超时时间, 所有的操作都必须是当前的提供者才可以修改, 因此有个参数
T me
, 返回值判断是否修改成功
public synchronized boolean touch(T me, long time, TimeUnit unit) { ... }
另外有个几个简单方法, 分别是默认超时时间的10倍和20倍: touchTenFold
, touchTwentyFold
- 有一个断言方法认定当前是自己
assertIsMe
, 如果不是自己会抛出IllegalStateException
的异常
public TimeoutTaskManager<T> assertIsMe(T me, String format, Object... args) throws IllegalStateException { ... }
一些其他方法有用的方法
- 可以添加一个提供者切换时候的监听器, 有时候切换的时候需要做一些清理工作
public TimeoutTaskManager<T> addChangeListeners(BiConsumer<T, T> cn) { ... }
- 如果任务有共享数据可以放置到缓存中, 注意线程安全需要自己保证
public TimeoutTaskManager<T> putCache(String key, Object cache) { ... }
- 还提供了线程的同步的方法, 不会在
doing
的过程中产生provider
的切换, 注意:不要产生死锁
public synchronized TimeoutTaskManager<T> ifMe(T me, Runnable doing) throws IllegalStateException { ... }
详细代码在 Gitee
TimeoutTaskManager
(完)
网友评论