IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 定时器Timer -> 正文阅读

[Java知识库]定时器Timer

目录

一、定时器应用

二、定时器设计

1. 接口设计

2. 实现方式

2.1 红黑树

2.2 最小堆

2.3 时间轮

源码



一、定时器应用

  • 心跳检测/周期任务
  • 倒计时/超时机制

对于服务端而言,驱动服务端的事件主要有两种:网络事件、定时事件。

不同的框架中,这两种事件有不同的实现方式:

第一种:网络事件和时间事件在一个线程中配合使用。如:Nginx、Redis;

第二种:网络事件和时间事件在不同线程中处理。如skynet。

// 第一种:
while (!quit) {
    time_t now = time(NULL);
    int timeout = get_nearest_timer() - now;
    if (timeout < 0) timeout = 0;
    int nEvent = epoll_wait(epfd, ev, nev, timeout);
    for (int i = 0; i < nEvent; i++) {
        // 处理网络事件
    }
    update_timer();  // 处理时间事件
}
// 第二种
void *thread_timer(void *p) {
    init_timer();
    while (!quit) {
        update_timer();  // 更新定时器,并处理时间事件或把时间事件发送到MQ
        sleep(t);        // t要小于时间精度
    }
    clear_timer();
    return NULL;
}

二、定时器设计

1. 接口设计

// 初始化timer
void init_timer();

// 添加timer
Node *add_timer(int expire, callback cb);

// 删除timer
bool del_timer(Node *node);

// 找到最近的定时任务
Node *find_nearest_timer();

// 更新timer
void update_timer();

// 清除timer
void clear_timer();

2. 实现方式

  • 红黑树
  • 最小堆
  • 跳表
  • 时间轮

待确认

实现方式增删查查找最小节点应用场景
RBTreeO(log2^N)O(log2N)Nginx Redis
MinHeap

增查:O(log2N)

删:O(N) ,可通过辅助数据结构(hash table)快速定位节点,加快删除操作

O(1)常用?
SkipList

O(log2N)

空间复杂度O(1.5N)

O(1)
时间轮O(1)O(1)Linux内核

2.1 红黑树

这里需要和STL的map区分,因为这里可能存在相同的key,而map的key是唯一的。可以考虑使用multimap,也可以自己实现。

nginx中的实现如下:

void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp,
    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
    ngx_rbtree_node_t **p;
    for ( ;; ) {
        // 注意:key相同时,p选择right
        p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
            ? &temp->left : &temp->right;
        if (*p == sentinel) {
            break;
        }
        temp = *p;
    }
    *p = node;
    node->parent = temp;
    node->left = sentinel;
    node->right = sentinel;
    ngx_rbt_red(node);
}

2.2 最小堆

完全?叉树:若?叉树的深度为 h ,除了 h 层外,其他层的节点数都是该层所能容纳节点的最?
数量(满?2^n),且 h 层都集中在最左侧;

最小堆特性:
? 1. 是?颗完全?叉树;
? 2. 某?个节点的值总是?于等于它的?节点的值;
? 3. 堆中每个节点的?树都是最?堆;

增加节点步骤:

? ? ? ? 为了满足完全二叉树特性,把新增的节点放到最后的位置,然后考虑是否需要上升。如添加“4”,4为5的左子树,4<5 需要上升。

删除节点步骤:

? ? ? ?删除前需要查询节点是否存在,最小堆的查询效率是O(n),查询到节点后,把该节点和最后一个节点交换位置,先考虑下降操作,如果操作失败则考虑上升操作,最后删除最后一个节点

如删除“1”,首先1和3交换,3和2交换,再删除末尾节点;

如删除“9“,首先9和3交换,3不能下沉了,考虑上升操作,3和7交换。

?

2.3 时间轮

单层时间轮

如何实现:客户端每 5 秒钟发送?跳包;服务端若 10 秒内没收到?跳数据,则清除连接;

实际在开发过程中,若收到除了?跳包的其他数据,?跳检测也算通过,在这?为了简化流程,只
判断?跳包;


作为对?:我们假设使? map<int, conn*> 来存储所有连接数;每秒检测 map 结构,那么每秒需
要遍历所有的连接,如果这个map结构包含?万条连接,那么我们做了很多?效检测;考虑极端
情况,刚添加进来的连接,下?秒就需要去检测,实际上只需要10秒后检测就?了;那么我们考
虑使?时间轮来检测;


注意:这个例?只是?来帮助理解时间轮,不代表实际解决?案;

TODO


源码

代码:0voice/7.1 timers at main · T-Mac1991/0voice · GitHub

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-09 11:31:13  更:2021-12-09 11:32:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:45:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码