java延時隊列的使用

業務場景:  需要在定時器中查詢某個人的狀態(相當於實時查詢),判斷是否需要推送消息,推送消息的機制是20分鐘之後,並且需要無限推送,使用delayQueue來實現

實現細節:  定時器掃描任務,維護一個需要推送消息的map,key爲mobile,value爲延時推送消息對象,同時維護一個queue,這個queue存放需要推送的對象

每次先衝map中取出推送對象(根據mobile獲取):

   1.獲取不到(說明上一次這個人不需要推送消息),在判斷本次是否需要推送,如果需要推送,則存入map,同時讓多線程取執行,否則不進行處理

2.獲取到了(說明上一次需要推送,並且延時隊列中未消費),判斷本次是否需要推送,如果需要推送,存入map,推送消息

否則移除map和deayQueue中的對象,目的是保證map和delayQueue中一個人(手機號的唯一性)

  這樣就保證了能循環間隔推送,並且當本次查詢的不需要推送的話,直接取消上一次沒有推送的任務(因爲我們需要實時監測是否需要推送)

 

 

 

定時器代碼:

private DelayQueue<SalesMessage> delayedQueue;

    /**
     * 維護需要推送的對象
     */
    private Map<String,SalesMessage> salesMap;

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

 

 

@Async
    @Scheduled(fixedDelay = 60000)
    public void searchUnSaveCustomer(){
        log.info("進入查詢銷售顧問未錄入的顧客定時任務.......");
        //拉取所有銷售顧問列表
        QueryWrapper<SysAccount> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("role_id",RoleEnum.SELLER.getValue());
        List<SysAccount> sysList = Optional.ofNullable(sysAccountDAO.list(queryWrapper)).orElse(new ArrayList<>());
        if(!CollectionUtils.isEmpty(sysList)){
            for (SysAccount account : sysList) {
                Store store = Optional.ofNullable(storeDAO.getById(account.getStoreId())).orElse(new Store());
                if(ObjectUtils.isEmpty(store.getId()) || ObjectUtils.isEmpty(store.getDealerId()) || StringUtils.isEmpty(account.getMobile())){
                    log.warn("查無店鋪/經銷商信息.....");
                    continue;
                }
                List<WorkStatusIteam> list = new ArrayList<>();
                if(1 == Integer.parseInt(isChongQing)){
                    list = this.queryWorkStatus(store.getDealerId(),null);
                }
                if(CollectionUtils.isEmpty(list)){
                    return;
                }
                long n = list.stream().filter(x -> x.getChangeStatus().equals(WorkStatusEnum.IN_THE_RECEPTION.getValue())).count();
                //long n = customerRecordDAO.count();
                //查詢當天該銷售顧問錄入的顧客數量
                QueryWrapper<Customer> wrapper = new QueryWrapper<>();
                wrapper.eq("sales_id",account.getId());
                wrapper.eq("store_id",account.getStoreId());
                wrapper.apply("date(create_time) = CURDATE()");
                int count = customerDAO.count(wrapper);
                String mobile = account.getMobile();
                //判斷是否存在對象
                SalesMessage salesMessage = salesMap.get(mobile);
                if(ObjectUtils.isEmpty(salesMessage)){
                    //不存在,判斷是否需要推送
                    if(count != n){
                        this.pushMessage(n,count,mobile);
                    }
                }else{
                    //存在,判斷當前是否需要推送,需要推送就維持之前的推送隊列,否則,就移除隊列中對應的數據
                    if(count == n){
                        //說明當前不需要推送,那麼久移除隊列中對應的數據
                        if(!delayedQueue.isEmpty()){
                            boolean remove = delayedQueue.remove(salesMessage);
                            log.info("當前狀態下,銷售顧問已經錄入了顧客,不需要推送消息,取消隊列任務:[{}]",remove);
                        }
                    }
                }
              }
            }
        }

延時消息對象代碼:

package com.hfepay.ai.store.changan.scheduled;

import lombok.Data;

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

/***
 * @ClassName: SalesMessage
 * @Description: 延時消息對象
 * @Author: wm_yu
 * @Create_time: 17:14 2020-1-9
 */
@Data
public class SalesMessage implements Delayed {

    /**
     * 顧問手機
     */
    private String mobile;
    /**
     * 消息內容
     */
    private String body;
    /**
     * 延遲時長,這個是必須的屬性因爲要按照這個判斷延時時長。
     */
    private long excuteTime;

    /**
     * 到期時間
     */
     private long expire;


    public SalesMessage(String mobile, String body, long excuteTime) {
        this.mobile = mobile;
        this.body = body;
        this.excuteTime = excuteTime;
        this.expire = System.currentTimeMillis() + excuteTime*1000;
    }

    /**
     * 需要實現的接口,獲得延遲時間   用過期時間-當前時間
     * @param unit
     * @return
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(this.expire - System.currentTimeMillis() , TimeUnit.MILLISECONDS);
    }

    /**
     * 用於延遲隊列內部比較排序   當前時間的延遲時間 - 比較對象的延遲時間
     * @param o
     * @return
     */
    @Override
    public int compareTo(Delayed o) {
        return (int) (o.getDelay(TimeUnit.MILLISECONDS) - this.getDelay(TimeUnit.MILLISECONDS));
    }
}

 

消費者代碼,一直去讀取queue中的對象,只有在延時時間到期,才能獲取到數據

package com.hfepay.ai.store.changan.scheduled;

import com.alibaba.fastjson.JSONObject;
import com.hfepay.ai.store.changan.service.GuanChuangProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;

import java.util.Map;
import java.util.concurrent.DelayQueue;

/***
 * @ClassName: SalesMessageConsumer
 * @Description:
 * @Author: wm_yu
 * @Create_time: 17:21 2020-1-9
 */
@AllArgsConstructor
@Data
@Slf4j
public class SalesMessageConsumer implements Runnable {

    /**
     * 延時隊列 ,消費者從其中獲取消息進行消費
     */
    private DelayQueue<SalesMessage> queue;

    private GuanChuangProperties guanChuangProperties;

    private String isChongQing;

    private Map<String,SalesMessage> map;

    @Override
    public void run() {
        while (queue.size() > 0){
            try {
                SalesMessage salesMessage = queue.poll();
                if(!ObjectUtils.isEmpty(salesMessage)){
                    log.info("延時隊列獲取的數據:[{}],是否需要發送消息提醒:[{}]", JSONObject.toJSONString(salesMessage),!ObjectUtils.isEmpty(salesMessage));
                    String mobile = salesMessage.getMobile();
                    String body = salesMessage.getBody();
                    guanChuangProperties.sendMessage(Integer.parseInt(isChongQing),mobile,body);
                    //移除map中的對應數據
                    map.remove(mobile);
                    log.info("推送消息手機號:[{}],推送內容:[{}]",mobile,body);
                }
            } catch (Exception e) {
                log.info("獲取延時隊列數據異常,",e.getMessage(),e);
            }
        }
    }
}

 

 

 

 

發佈了93 篇原創文章 · 獲贊 26 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章