liusuyi
2026-05-18 0b8c8d8986a35c3e36db1503125e2dff79d6d10e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.ard.gb28181.transmit.event;
 
import com.ard.gb28181.common.ErrorCode;
import com.ard.gb28181.transmit.event.sip.MessageEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.DelayQueue;
 
/**
 * @author lin
 */
@Slf4j
@Component
public class MessageSubscribe {
 
    private final Map<String, MessageEvent<?>> subscribes = new ConcurrentHashMap<>();
 
    private final DelayQueue<MessageEvent<?>> delayQueue = new DelayQueue<>();
 
    @Scheduled(fixedDelay = 200)
    public void execute() {
        // 1. 使用 poll() 替代 take()
        // poll() 会立即返回:如果有已超期的任务则返回,否则返回 null
        MessageEvent<?> take = delayQueue.poll();
 
        // 2. 循环处理所有已超期的任务
        while (take != null) {
            try {
                // 执行回调(超时处理)
                if (take.getCallback() != null) {
                    take.getCallback().run(ErrorCode.ERROR486.getCode(), "消息超时未回复", null);
                }
                subscribes.remove(take.getKey());
            } catch (Exception e) {
                // 建议捕获 Exception 而不是 RuntimeException,防止业务异常导致循环中断
                log.error("[超时检查] 处理超时任务异常", e);
            }
            // 3. 继续尝试获取下一个已超期的任务
            take = delayQueue.poll();
        }
        // 4. 如果 poll() 返回 null,说明当前没有超时的任务,方法直接结束
        // 线程释放,等待下一次 200ms 调度
    }
 
 
    public void addSubscribe(MessageEvent<?> event) {
        MessageEvent<?> messageEvent = subscribes.get(event.getKey());
        if (messageEvent != null) {
            subscribes.remove(event.getKey());
            delayQueue.remove(messageEvent);
        }
        subscribes.put(event.getKey(), event);
        delayQueue.offer(event);
    }
 
    public MessageEvent<?> getSubscribe(String key) {
        return subscribes.get(key);
    }
 
    public void removeSubscribe(String key) {
        if(key == null){
            return;
        }
        MessageEvent<?> messageEvent = subscribes.get(key);
        if (messageEvent != null) {
            subscribes.remove(key);
            delayQueue.remove(messageEvent);
        }
    }
 
    public boolean isEmpty(){
        return subscribes.isEmpty();
    }
 
    public Integer size() {
        return subscribes.size();
    }
}