博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
超时机制的简单实现
阅读量:6275 次
发布时间:2019-06-22

本文共 12257 字,大约阅读时间需要 40 分钟。

hot3.png

在使用HttpClient过程中, 对于链接超时以及请求超时的设置是必不可少的。

HttpClient httpClient = new HttpClient();httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(params.getConnectionTimeout());httpClient.getHttpConnectionManager().getParams().setSoTimeout(params.getSoTimeout());

相对于客户端,服务端(譬如nginx)对于接收的多请求处理更为复杂。

请求数比较多的情况下,怎么判断每个请求的超时时间并加以处理?

  1. 将客户端的每个请求按照请求顺序依次放入有序集合(ArrayList)中,启动一个线程循环遍历该集合,如果发现有请求超时则中断该请求;
  2. 将客户端的每个请求依次放入排序集合(TreeMap)中,启动一个线程循环遍历每个元素,如果发现当前遍历的对象未超时,则停止后续遍历,已超时的则直接中断请求;
  3. 将客户端的每个请求按照超时时间存入排序阻塞集合(DelayQueue)中,启动线程获取集合数据时如果未到超时时间则阻塞线程。

分析以上三种方案:

  1. 每次需要循环遍历所有数据比对,如果说数据比较多的情况下耗时时间还是比较长的;如果数据比较少,并且超时时间未到,则cpu会消耗比较大(while(true));
  2. 不用遍历所有数据,但会跟1存在cpu消耗比较大的情况;
  3. 借鉴了2的优势,同时又不会浪费cpu资源。

现在可以看下三种方案的简单实现:

第一种方案
package tech.zhaohuijun;/** * Vincent 创建于 2017/03/22. */public class Request {    //服务器收到请求时间,单位毫秒    private long receivetime;    //超时时间,单位毫秒    private long timeout;    //请求状态 1请求中2请求完成3请求超时    private int status=1;    //请求名称    private String name;    public Request(String name) {        this.name = name;    }    public void interrupt() {        this.status = 3;        System.out.println("请求"+this.getName()+"过期,已被中断");    }    public int getStatus() {        return status;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public void setStatus(int status) {        this.status = status;    }    public long getReceivetime() {        return receivetime;    }    public void setReceivetime(long receivetime) {        this.receivetime = receivetime;    }    public long getTimeout() {        return timeout;    }    public void setTimeout(long timeout) {        this.timeout = timeout;    }}
package tech.zhaohuijun;import java.util.List;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;/** * Vincent 创建于 2017/3/22. */public class ServerTimeoutThread implements Runnable {    private List
requestList; private CountDownLatch countDownLatch; public ServerTimeoutThread(List
requestList, CountDownLatch countDownLatch) { this.requestList = requestList; this.countDownLatch = countDownLatch; } @Override public void run() { while (true) { for (Request request : requestList) { if (request.getReceivetime() + request.getTimeout() <= System.currentTimeMillis() && request.getStatus() == 1) { request.interrupt(); countDownLatch.countDown(); } } //为了测试cpu循环占用的问题,暂停500ms打印 try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("------"); } }}
package tech.zhaohuijun;import java.util.ArrayList;import java.util.List;import java.util.concurrent.CountDownLatch;/** * Vincent 创建于 2017/3/22. */public class Server {    private static final List
REQUEST_LIST =new ArrayList<>(); public static void main(String[] args) throws InterruptedException { //添加多个请求,超时时间不一样 long currentTimeMillis = System.currentTimeMillis(); //超时时间5s Request request1=new Request("request-1"); request1.setReceivetime(currentTimeMillis); request1.setTimeout(5000); //超时时间15s Request request2=new Request("request-2"); request2.setReceivetime(currentTimeMillis); request2.setTimeout(15000); //超时时间10s Request request3=new Request("request-3"); request3.setReceivetime(currentTimeMillis); request3.setTimeout(10000); REQUEST_LIST.add(request1); REQUEST_LIST.add(request2); REQUEST_LIST.add(request3); CountDownLatch countDownLatch=new CountDownLatch(REQUEST_LIST.size()); //启动线程处理超时 Thread thread=new Thread(new ServerTimeoutThread(REQUEST_LIST,countDownLatch)); thread.setDaemon(true); thread.start(); countDownLatch.await(); }}

输出:

------------------------------------------------------------请求request-1过期,已被中断------------------------------------------------------------请求request-3过期,已被中断------------------------------------------------------------请求request-2过期,已被中断
第二种方案
package tech.zhaohuijun;/** * Vincent 创建于 2017/03/22. */public class Request {    //服务器收到请求时间,单位毫秒    private long receivetime;    //超时时间,单位毫秒    private long timeout;    //请求状态 1请求中2请求完成3请求超时    private int status=1;    //请求名称    private String name;    public Request(String name) {        this.name = name;    }    public void interrupt() {        this.status = 3;        System.out.println("请求"+this.getName()+"过期,已被中断");    }    public int getStatus() {        return status;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public void setStatus(int status) {        this.status = status;    }    public long getReceivetime() {        return receivetime;    }    public void setReceivetime(long receivetime) {        this.receivetime = receivetime;    }    public long getTimeout() {        return timeout;    }    public void setTimeout(long timeout) {        this.timeout = timeout;    }}
package tech.zhaohuijun;import java.util.Map;import java.util.Set;import java.util.TreeMap;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;/** * Vincent 创建于 2017/3/22. */public class ServerTimeoutThread implements Runnable {    private TreeMap
requestTreeMap; private CountDownLatch countDownLatch; public ServerTimeoutThread(TreeMap
requestTreeMap, CountDownLatch countDownLatch) { this.requestTreeMap = requestTreeMap; this.countDownLatch = countDownLatch; } @Override public void run() { while (true) { Set
> entrySet = requestTreeMap.entrySet(); for (Map.Entry
entry : entrySet) { Request request = entry.getValue(); if (entry.getKey() > System.currentTimeMillis()) { break; } if (request.getStatus() == 1) { request.interrupt(); countDownLatch.countDown(); } } //为了测试cpu循环占用的问题,暂停500ms打印 try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("------"); } }}
package tech.zhaohuijun;import java.util.TreeMap;import java.util.concurrent.CountDownLatch;/** * Vincent 创建于 2017/3/22. */public class Server {    private static final TreeMap
REQUEST_TREE_MAP =new TreeMap<>(); public static void main(String[] args) throws InterruptedException { //添加多个请求,超时时间不一样 long currentTimeMillis = System.currentTimeMillis(); //超时时间5s Request request1=new Request("request-1"); request1.setReceivetime(currentTimeMillis); request1.setTimeout(5000); //超时时间15s Request request2=new Request("request-2"); request2.setReceivetime(currentTimeMillis); request2.setTimeout(15000); //超时时间10s Request request3=new Request("request-3"); request3.setReceivetime(currentTimeMillis); request3.setTimeout(10000); REQUEST_TREE_MAP.put(request1.getReceivetime()+request1.getTimeout(),request1); REQUEST_TREE_MAP.put(request2.getReceivetime()+request2.getTimeout(),request2); REQUEST_TREE_MAP.put(request3.getReceivetime()+request3.getTimeout(),request3); CountDownLatch countDownLatch=new CountDownLatch(REQUEST_TREE_MAP.size()); //启动线程处理超时 Thread thread=new Thread(new ServerTimeoutThread(REQUEST_TREE_MAP,countDownLatch)); thread.setDaemon(true); thread.start(); countDownLatch.await(); }}

输出:

------------------------------------------------------------请求request-1过期,已被中断------------------------------------------------------------请求request-3过期,已被中断------------------------------------------------------------请求request-2过期,已被中断
第三种方案:
package tech.zhaohuijun;import java.util.concurrent.Delayed;import java.util.concurrent.TimeUnit;/** * Vincent 创建于 2017/03/22. */public class Request implements Delayed {    //服务器收到请求时间,单位毫秒    private long receivetime;    //超时时间,单位毫秒    private long timeout;    //请求状态 1请求中2请求完成3请求超时    private int status=1;    //请求名称    private String name;    public Request(String name) {        this.name = name;    }    public void interrupt() {        this.status = 3;        System.out.println("请求"+this.getName()+"过期,已被中断");    }    public int getStatus() {        return status;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public void setStatus(int status) {        this.status = status;    }    public long getReceivetime() {        return receivetime;    }    public void setReceivetime(long receivetime) {        this.receivetime = receivetime;    }    public long getTimeout() {        return timeout;    }    public void setTimeout(long timeout) {        this.timeout = timeout;    }    @Override    public long getDelay(TimeUnit unit) {        return unit.convert(this.getReceivetime()+this.getTimeout()-System.currentTimeMillis(),TimeUnit.MILLISECONDS);    }    @Override    public int compareTo(Delayed o) {        if(o == null || ! (o instanceof Request)) return 1;        if(o == this) return 0;        Request s = (Request)o;        long l1 = this.getReceivetime() + this.getTimeout();        long l2 = s.getReceivetime() + s.getTimeout();        if (l1 > l2) {            return 1;        }else if (l1 == l2) {            return 0;        }else {            return -1;        }    }}
package tech.zhaohuijun;import java.util.concurrent.CountDownLatch;import java.util.concurrent.DelayQueue;/** * Vincent 创建于 2017/3/22. */public class ServerTimeoutThread implements Runnable {    private DelayQueue
requestDelayQueue; private CountDownLatch countDownLatch; public ServerTimeoutThread(DelayQueue
requestDelayQueue, CountDownLatch countDownLatch) { this.requestDelayQueue = requestDelayQueue; this.countDownLatch = countDownLatch; } @Override public void run() { while (true) { Request request = null; try { request = requestDelayQueue.take(); if (request.getStatus() == 1) { request.interrupt(); countDownLatch.countDown(); } System.out.println("------"); } catch (InterruptedException e) { e.printStackTrace(); } } }}
package tech.zhaohuijun;import java.util.concurrent.CountDownLatch;import java.util.concurrent.DelayQueue;/** * Vincent 创建于 2017/3/22. */public class Server {    private static final DelayQueue
REQUEST_DELAY_QUEUE =new DelayQueue<>(); public static void main(String[] args) throws InterruptedException { //添加多个请求,超时时间不一样 long currentTimeMillis = System.currentTimeMillis(); //超时时间5s Request request1=new Request("request-1"); request1.setReceivetime(currentTimeMillis); request1.setTimeout(5000); //超时时间15s Request request2=new Request("request-2"); request2.setReceivetime(currentTimeMillis); request2.setTimeout(15000); //超时时间10s Request request3=new Request("request-3"); request3.setReceivetime(currentTimeMillis); request3.setTimeout(10000); REQUEST_DELAY_QUEUE.put(request1); REQUEST_DELAY_QUEUE.put(request2); REQUEST_DELAY_QUEUE.put(request3); CountDownLatch countDownLatch=new CountDownLatch(REQUEST_DELAY_QUEUE.size()); //启动线程处理超时 Thread thread=new Thread(new ServerTimeoutThread(REQUEST_DELAY_QUEUE,countDownLatch)); thread.setDaemon(true); thread.start(); countDownLatch.await(); }}

输出:

请求request-1过期,已被中断------请求request-3过期,已被中断------请求request-2过期,已被中断------

转载于:https://my.oschina.net/vincentzhao/blog/864548

你可能感兴趣的文章
Django 文件下载功能
查看>>
走红日本 阿里云如何能够赢得海外荣耀
查看>>
磁盘空间满引起的mysql启动失败:ERROR! MySQL server PID file could not be found!
查看>>
点播转码相关常见问题及排查方式
查看>>
[arm驱动]linux设备地址映射到用户空间
查看>>
弗洛伊德算法
查看>>
【算法之美】求解两个有序数组的中位数 — leetcode 4. Median of Two Sorted Arrays
查看>>
精度 Precision
查看>>
Android——4.2 - 3G移植之路之 APN (五)
查看>>
Linux_DHCP服务搭建
查看>>
[SilverLight]DataGrid实现批量输入(like Excel)(补充)
查看>>
秋式广告杀手:广告拦截原理与杀手组织
查看>>
翻译 | 摆脱浏览器限制的JavaScript
查看>>
闲扯下午引爆乌云社区“盗窃”乌云币事件
查看>>
02@在类的头文件中尽量少引入其他头文件
查看>>
JAVA IO BIO NIO AIO
查看>>
input checkbox 复选框大小修改
查看>>
网吧维护工具
查看>>
BOOT.INI文件参数
查看>>
vmstat详解
查看>>