轮询功能java实现

一、业务背景

由于项目需要满足大量轮询业务需求,需升级原有的轮询功能。改造过程中发现延时队列(DelayQueue)可以满足业务需求,但是论证后发现延时队列的查询、更新和删除时间复杂度为O(N),因此要对延时队列进行优化。

二、延时队列介绍

延时队列使用优先队列(Priority)+延时器(Delay)实现,优先队列可以保证根节点为排序元素的最大值或者最小值,因此轮询实体在重写延时器(Delay)的CompaerTo方法后,可以保证优先队列的根节点始终为最近到期的轮询实体。

三、优化

使用HashMap索引轮询实体,从而使查询和更新的时间复杂度降为O(1),但是删除的时间复杂度并不能优化到O(logn),因为优先队列删除的时间复杂度为O(N)。如果使用红黑树来实现优先队列的功能可以做到删除时间复杂度为O(logN),但是红黑数依然使用时间作为排序规则,所以并不能在这个维度下来做延时队列的删除。因此最终还是选用优先队列来实现轮询功能

四、代码实现

1、延时队列

import com.hey.bean.dto.ModemPollDto;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ModemPollQueue {
  private final transient ReentrantLock lock = new ReentrantLock();
  
  private final Map<String, ModemPollDto> map = new HashMap<>();
  
  private final PriorityQueue<ModemPollDto> q = new PriorityQueue<>();
  
  private Thread leader;
  
  private final Condition available = this.lock.newCondition();
  
  public boolean put(String k, ModemPollDto e) {
    ReentrantLock lock = this.lock;
    lock.lock();
    try {
      this.map.put(k, e);
      this.q.add(e);
      if (this.q.peek() == e) {
        this.leader = null;
        this.available.signal();
      } 
      return true;
    } finally {
      lock.unlock();
    } 
  }
  
  public ModemPollDto take() throws InterruptedException {
    ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
      while (true) {
        ModemPollDto first = this.q.peek();
        if (first == null) {
          this.available.await();
          continue;
        } 
        long delay = first.getDelay(TimeUnit.NANOSECONDS);
        if (delay <= 0L) {
          this.q.poll();
          this.map.remove(first.getModemId());
          return first;
        } 
        first = null;
        if (this.leader != null) {
          this.available.await();
          continue;
        } 
        Thread thisThread = Thread.currentThread();
        this.leader = thisThread;
        try {
          this.available.awaitNanos(delay);
        } finally {
          if (this.leader == thisThread)
            this.leader = null; 
        } 
      } 
    } finally {
      if (this.leader == null && this.q.peek() != null)
        this.available.signal(); 
      lock.unlock();
    } 
  }
  
  public ModemPollDto get(Object o) {
    ReentrantLock lock = this.lock;
    lock.lock();
    try {
      return this.map.get(o);
    } finally {
      lock.unlock();
    } 
  }
  
  public int size() {
    ReentrantLock lock = this.lock;
    lock.lock();
    try {
      return this.map.size();
    } finally {
      lock.unlock();
    } 
  }
  
  public boolean remove(String modemId) {
    ReentrantLock lock = this.lock;
    lock.lock();
    try {
      ModemPollDto remove = this.map.remove(modemId);
      if (remove == null)
        return false; 
      return this.q.remove(remove);
    } finally {
      lock.unlock();
    } 
  }
  
  public ModemPollDto[] toArray() {
    ReentrantLock lock = this.lock;
    lock.lock();
    try {
      return this.q.<ModemPollDto>toArray(new ModemPollDto[this.q.size()]);
    } finally {
      lock.unlock();
    } 
  }
}

2、轮询实体

import java.util.Date;
import java.util.Objects;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ModemPollDto implements Delayed {
  private Integer id;
  
  private String modemName;
  
  private String modemId;
  
  private String modemIp;
  
  private Integer modemType;
  
  private Integer beamNum;
  
  private Integer polingNotWithdraw;
  
  private Integer polingSlot;
  
  private Integer currentPollCnt;
  
  private Integer pollMultiple;
  
  private Long time;
  
  private Long passTime;
  
  private Integer pollCount;
  
  private Integer pollResponseCount;
  
  public boolean equals(Object o) {
    if (this == o)
      return true; 
    if (o == null || getClass() != o.getClass())
      return false; 
    ModemPollDto that = (ModemPollDto)o;
    return Objects.equals(this.modemId, that.modemId);
  }
  
  public long getDelay(TimeUnit unit) {
    return this.time.longValue() - System.currentTimeMillis();
  }
  
  public int compareTo(Delayed o) {
    ModemPollDto item = (ModemPollDto)o;
    long diff = this.time.longValue() - item.time.longValue();
    if (diff < 0L)
      return -1; 
    return 1;
  }
}

3、轮询类

public class RemPollJob {
  @Async
  public void poll() {
    ModemPollQueue queue = PollTaskConstant.remotePoll;
    while (true) {
      try {
        ModemPollDto take = queue.take();
        if (take.getCurrentPollCnt().equals(Integer.valueOf(take.getPolingSlot().intValue() - 1))) {
          addLeaveTheNetCaveat(take, take.getCurrentPollCnt().intValue());
        } else if (take.getCurrentPollCnt().intValue() >= take.getPolingSlot().intValue()) {
          if (take.getPolingNotWithdraw().intValue() == 0) {
            leave(take);
            continue;
          } 
        } 
        take.setCurrentPollCnt(Integer.valueOf(take.getCurrentPollCnt().intValue() + 1));
        take.setPollCount(Integer.valueOf(take.getPollCount().intValue() + 1));
        take.setPassTime(Long.valueOf(System.currentTimeMillis() - take.getTime().longValue()));
        take.setTime(Long.valueOf(System.currentTimeMillis() + (take.getPollMultiple().intValue() * 1000)));
        queue.put(take.getModemId(), take);
        issuePoll(take);
      } catch (Exception e) {
        e.printStackTrace();
      } 
    } 
  }
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值