文档章节

超时机制的简单实现

清尘V
 清尘V
发布于 2017/03/22 11:26
字数 1622
阅读 13
收藏 0

在使用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<Request> requestList;

    private CountDownLatch countDownLatch;


    public ServerTimeoutThread(List<Request> 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> 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<Long, Request> requestTreeMap;

    private CountDownLatch countDownLatch;


    public ServerTimeoutThread(TreeMap<Long, Request> requestTreeMap, CountDownLatch countDownLatch) {
        this.requestTreeMap = requestTreeMap;
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        while (true) {
            Set<Map.Entry<Long, Request>> entrySet = requestTreeMap.entrySet();
            for (Map.Entry<Long, Request> 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<Long,Request> 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<Request> requestDelayQueue;

    private CountDownLatch countDownLatch;


    public ServerTimeoutThread(DelayQueue<Request> 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> 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过期,已被中断
------

© 著作权归作者所有

清尘V

清尘V

粉丝 41
博文 107
码字总数 47780
作品 0
青岛
程序员
私信 提问
如何高效维持网络长连接:手把手教你实现 自适应的心跳保活机制

前言 当实现具备实时性需求时,我们一般会选择长连接的通信方式 而在实现长连接方式时,存在很多性能问题,如 长连接保活 今天,我将 手把手教大家实现自适应的心跳保活机制,从而能高效维持...

Carson_Ho
08/26
0
0
谈谈 ANR 之 Service 超时

1. 核心源码 关键类 路径(/frameworks/base/) ActiveServices.java services/core/java/com/android/server/am/ActiveServices.java ActivityManagerService.java services/core/java/com/......

DeepCoder
04/29
0
0
Okio精简高效的IO库

本节主要讲讲Okhttp底层使用的IO库--Okio,Okio同样是Square公司推出的增强型IO处理库,旨在增强原生Java IO流的处理,以更加简便,高效的方式处理IO流操作。接下来我会从以下方面来分析它。...

Ihesong
2017/11/28
0
0
一种极简的异步超时处理机制设计与实现(C#版)

1.引言 当执行某些动作之后,会期待反馈。最终要么是得到了结果,要么就是超时了。当超时发生时,可能是期望得到通知,或是希望能自动重试,等等。于是设计了一种通用的异步超时的处理机制,...

三人行工作室
05/28
0
0
基于redis的分布式锁设计实现

分布式锁介绍 分布式并发环境下,为了保证事务操作的原子性,需要引入分布式锁来保证一连串行为是原子性操作 例如经典的自增1操作 假设当前有两个线程要执行上面的操作,要保证线程a在保存新...

谢随安
03/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Qt程序打包发布方法(使用官方提供的windeployqt工具)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/toTheUnknown/article/details/81748179 如果使用到了Qt ...

shzwork
23分钟前
4
0
MainThreadSupport

MainThreadSupport EventBus 3.0 中的代码片段. org.greenrobot.eventbus.MainThreadSupport 定义一个接口,并给出默认实现类. 调用者可以在EventBus的构建者中替换该实现. public interface ...

马湖村第九后羿
44分钟前
3
0
指定要使用的形状来代替文字的显示

控制手机键盘弹出的功能只能在ios上实现,安卓是实现不了的,所以安卓只能使用type类型来控制键盘类型,例如你要弹出数字键盘就使用type="number",如果要弹出电话键盘就使用type="tel",但这...

前端老手
54分钟前
6
0
总结:Raft协议

一、Raft协议是什么? 分布式一致性算法。即解决分布式系统中各个副本数据一致性问题。 二、Raft的日志广播过程 发送日志到所有Followers(Raft中将非Leader节点称为Follower)。 Followers收...

浮躁的码农
今天
7
0
Flask-admin Model View字段介绍

Model View字段介绍 can_create = True 是否可以创建can_edit = True 是否可以编辑can_delete = True 是否可以删除list_template = 'admin/model/list.html' 修改显......

dillonxiao
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部