当前位置: 首页 > news >正文

Java超时控制的实现

基本原理

  • 采用LockSupport的parkNanos和unpack方法
  • 在另外一个线程中结果回来,unpack一下,返回;否则就等待超时返回(超时采用一线程轮询 + lock的condition的await 双重保险)

实例

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 
 * Created by codecraft on 2015/8/26.
 */
public class DefaultFuture {
    private static final Map<Long, DefaultFuture> FUTURES = new ConcurrentHashMap<Long, DefaultFuture>();
    private final long id;
    private final Lock lock = new ReentrantLock();
    private final Condition done = lock.newCondition();
    private volatile Response response;
    private final long start = System.currentTimeMillis();
    private final int timeout;
    public DefaultFuture(long id,int timeout) {
        this.id = id;
        this.timeout = timeout;
    }
    private long getStartTimestamp() {
        return start;
    }
    public int getTimeout() {
        return timeout;
    }
    public boolean isDone() {
        return response != null;
    }
    public long getId() {
        return id;
    }
    public Object get(int timeout){
        if (timeout <= 0) {
            timeout = 1000;
        }
        if (! isDone()) {
            long start = System.currentTimeMillis();
            lock.lock();
            try {
                while (! isDone()) {
                    done.await(timeout, TimeUnit.MILLISECONDS);
                    if (isDone() || System.currentTimeMillis() - start > timeout) {
                        break;
                    }
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
            if (! isDone()) {
//                throw new RuntimeException("timeout");
                System.out.println("timeout");
            }
        }
        return response;
    }
    private void doReceived(Response res) {
        lock.lock();
        try {
            response = res;
            if (done != null) {
                done.signal();
            }
        } finally {
            lock.unlock();
        }
    }
    public static void received(Response response) {
        try {
            DefaultFuture future = FUTURES.remove(response.getId());
            if (future != null) {
                future.doReceived(response);
            } else {
                System.out.println("The timeout response finally returned at "
                        + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))
                        + ", response ");
            }
        } finally {
//            CHANNELS.remove(response.getId());
        }
    }
    private static class RemotingInvocationTimeoutScan implements Runnable {
        public void run() {
            while (true) {
                try {
                    for (DefaultFuture future : FUTURES.values()) {
                        if (future == null || future.isDone()) {
                            continue;
                        }
                        if (System.currentTimeMillis() - future.getStartTimestamp() > future.getTimeout()) {
                            // create exception response.
                            Response timeoutResponse = new Response(future.getId());
                            // handle response.
                            DefaultFuture.received(timeoutResponse);
                        }
                    }
                    Thread.sleep(30);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        }
    }
    static {
        Thread th = new Thread(new RemotingInvocationTimeoutScan(), "ResponseTimeoutScanTimer");
        th.setDaemon(true);
        th.start();
    }
    public static void main(String[] args){
        int timeout = 1000;
        System.out.println("start");
        final long start = System.currentTimeMillis();
        final DefaultFuture future = new DefaultFuture(1,timeout);
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (System.currentTimeMillis() - start < 2000) {
                    //sleep
                }
                Response response = new Response();
                response.setResult("hello");
                future.doReceived(response);
            }
        }).start();
        Object response = future.get(timeout);
        System.out.println(System.currentTimeMillis() - start);
        System.out.println("res "+response);
    }
}

参考

  • dubbo-DefaultFuture

相关文章:

  • HeadFirst设计模式(三) - 装饰者模式
  • PHP基本语法
  • linux下无法删除文件的原因
  • Python学习(18)面向对象
  • 神经网络学习入门 -01
  • Calendar获取时间的月和日
  • php提示 Notice: Use of undefined constant name - assumed
  • 深入理解ThreadLocal
  • 沫沫金:EasyUI 固定列
  • Intellij idea断点 Debugger slow: Method breakpoints my dramatically slow down debugging
  • 分布式高并发系统如何保证对外接口的幂等性?
  • CentOS6 图形界面(gnome)安装
  • 钉钉客户端JS-API权限签名算法.NET版
  • Linux 卸载mysql-libs包出现错误
  • .net中的Queue和Stack
  • 2018一半小结一波
  • const let
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • Redis字符串类型内部编码剖析
  • Spark RDD学习: aggregate函数
  • Webpack 4 学习01(基础配置)
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 跨域
  • 面试总结JavaScript篇
  • 前端临床手札——文件上传
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 数据科学 第 3 章 11 字符串处理
  • 小程序开发中的那些坑
  • 用Canvas画一棵二叉树
  • ionic入门之数据绑定显示-1
  • #Linux杂记--将Python3的源码编译为.so文件方法与Linux环境下的交叉编译方法
  • (C++17) std算法之执行策略 execution
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (六) ES6 新特性 —— 迭代器(iterator)
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)拼包函数及网络封包的异常处理(含代码)
  • .Net mvc总结
  • .net Stream篇(六)
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)...
  • /proc/vmstat 详解
  • :中兴通讯为何成功
  • @Query中countQuery的介绍
  • @staticmethod和@classmethod的作用与区别
  • []利用定点式具实现:文件读取,完成不同进制之间的
  • [AIGC] Kong:一个强大的 API 网关和服务平台
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt
  • [Android学习笔记]ScrollView的使用
  • [BJDCTF 2020]easy_md5
  • [BUUCTF]-PWN:[极客大挑战 2019]Not Bad解析
  • [C#]winform部署yolov5-onnx模型
  • [C++][基础]1_变量、常量和基本类型
  • [C++]AVL树怎么转
  • [ChromeApp]指南!让你的谷歌浏览器好用十倍!