DelayQueue簡用

簡介

DelayQueue<E extends Delayed>
Delayed 元素的一個無界阻塞隊列呻惕,只有在延遲期滿時才能從中提取元素。該隊列的頭部 是延遲期滿后保存時間最長的Delayed 元素滥比。如果延遲都還沒有期滿亚脆,則隊列沒有頭部,并且 poll 將返回 null盲泛。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小于等于 0 的值時濒持,將發(fā)生到期。即使無法使用take 或 poll 移除未到期的元素寺滚,也不會將這些元素作為正常元素對待柑营。例如,size方法同時返回到期和未到期元素的計數(shù)村视。此隊列不允許使用 null 元素官套。

DelayQueue類圖結(jié)構(gòu)

5879294-0c7d2460f594360e.png

在源碼中看到 DelayQueue中內(nèi)部使用的是PriorityQueue存放數(shù)據(jù),使用ReentrantLock實現(xiàn)線程同步蚁孔,可知是阻塞隊列奶赔;

public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
    implements BlockingQueue<E> {

    private final transient ReentrantLock lock = new ReentrantLock();
    private final PriorityQueue<E> q = new PriorityQueue<E>();

元素實例

package com.cr.core.delay.entity;

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

/**
 *
 * 訂單超時實體類
 * Created by li on 2018/5/18.
 */
public class Order implements Delayed {

    /**
     * 訂單號
     */
    private long orderId;
    /**
     * 開始執(zhí)行時間
     */
    private long startTime;

    public Order(){

    }
    /**
     * orderId:訂單id
     * timeout:訂單超時時間,秒
     * */
    public Order(long orderId, int timeout){
        this.orderId = orderId;
        this.startTime = System.currentTimeMillis() + timeout*1000L;
    }
    /**
     * 返回當前對象的剩余延遲時間
     * @param unit
     * @return
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(startTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    /**
     * 比較當前對象與指定對象的順序(出棧順序)
     * @param o
     * @return
     */
    @Override
    public int compareTo(Delayed o) {
        if (o == this){
            return 0;
        }
        if(o instanceof Order){
            Order otherRequest = (Order)o;
            long otherStartTime = otherRequest.getStartTime();
            return (int)(this.startTime - otherStartTime);
        }
        return 0;
    }

    public long getOrderId() {
        return orderId;
    }

    public void setOrderId(long orderId) {
        this.orderId = orderId;
    }

    public long getStartTime() {
        return startTime;
    }

    public void setStartTime(long startTime) {
        this.startTime = startTime;
    }

    @Override
    public String toString() {
        return "DSHOrder{" +
                "orderId=" + orderId +
                ", startTime=" + startTime +
                '}';
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }
}

應(yīng)用實例

package com.cr.core.delay.service;

import com.cr.core.delay.entity.Order;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import java.util.concurrent.DelayQueue;

/**
 * Created by li on 2018/5/18.
 */
@Service
public class DelayService {

    private static final Logger log = Logger.getLogger(DelayService.class);


    private boolean start ;
    private DelayedListener listener;
    private DelayQueue<Order> delayQueue = new DelayQueue();
    //內(nèi)部接口勒虾,監(jiān)聽器啟動調(diào)本類start接口需要實現(xiàn)
    public interface DelayedListener{
        void delayedListener(Order order);
    }

    public void start(DelayedListener listener){
        if(start){
            return;
        }
        log.error("DelayService 啟動");
        start = true;
        this.listener = listener;
        new Thread(()->{
            try{
                while(true){
                    Order order = delayQueue.take();
                    if(DelayService.this.listener != null){
                        DelayService.this.listener.delayedListener(order);
                    }
                }
            }catch(Exception e){
                log.info(e.getMessage(),e);
            }
        }).start();
    }

    public void add(Order order){
        delayQueue.put(order);
    }

    public boolean remove(Order order){
        return delayQueue.remove(order);
    }

    public void add(long orderId){
        delayQueue.put(new Order(orderId,24*3600*1000));
    }

    public void remove(long orderId){
        Order[] array = delayQueue.toArray(new Order[]{});
        if(array == null || array.length <= 0){
            return;
        }
        Order target = null;
        for(Order order : array){
            if(order.getOrderId() == orderId){
                target = order;
                break;
            }
        }
        if(target != null){
            delayQueue.remove(target);
        }
    }
}

監(jiān)聽器實例

package com.cr.core.delay.service;

import com.cr.core.delay.entity.Order;
import com.cr.core.delay.entity.ThreadPoolUtil;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

import java.util.List;

/**
 * Created by li on 2018/5/18.
 */
public class StartupListener implements ApplicationListener {
    private static final Logger log = Logger.getLogger(StartupListener.class);

    @Autowired
    DelayService delayService;
    @Override
    public void onApplicationEvent(ApplicationEvent evt) {

        if (evt.getSource() == null) {
            return;
        }
        //自動收貨
        delayService.start((Order order)->{
            //異步來做
            ThreadPoolUtil.execute(()->{
                long orderId = order.getOrderId();
                //查庫判斷是否需要自動收貨
                log.error("自動確認收貨纺阔,onDelayedArrived():"+orderId);
                //從redis刪除
                //redisService.delete(Constants.RedisKey.DSH_PREFIX+orderId, RedisService.DB.DSH);
                log.error("自動確認收貨,刪除redis:"+orderId);
            });
        });
        //查找需要入隊的訂單
        ThreadPoolUtil.execute(()->{
            log.error("查找需要入隊的訂單");
            //掃描redis修然,找到所有可能的orderId
            List<String> keys = null;//redisService.scan(RedisService.DB.DSH);
            if(keys == null || keys.size() <= 0){
                return;
            }
            log.error("需要入隊的訂單keys:"+keys);
            //寫到DelayQueue
            for(String key : keys){
                Order order = null;//redisService.get(key, DSHOrder.class, RedisService.DB.DSH);
                log.error("讀redis笛钝,key:"+key);
                if(order != null){
                    //delayService.add(order);
                    log.error("訂單自動入隊:"+order.getOrderId());
                }
            }
        });
    }

}

使用場景

1质况、做訂單超時、支付超時玻靡、和第三方交互時冪等重試等等结榄;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市囤捻,隨后出現(xiàn)的幾起案子臼朗,更是在濱河造成了極大的恐慌,老刑警劉巖蝎土,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件视哑,死亡現(xiàn)場離奇詭異,居然都是意外死亡誊涯,警方通過查閱死者的電腦和手機挡毅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暴构,“玉大人跪呈,你說我怎么就攤上這事∪∮猓” “怎么了耗绿?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長砾隅。 經(jīng)常有香客問我误阻,道長,這世上最難降的妖魔是什么晴埂? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任堕绩,我火速辦了婚禮,結(jié)果婚禮上邑时,老公的妹妹穿的比我還像新娘奴紧。我一直安慰自己,他們只是感情好晶丘,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布黍氮。 她就那樣靜靜地躺著,像睡著了一般浅浮。 火紅的嫁衣襯著肌膚如雪沫浆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天滚秩,我揣著相機與錄音专执,去河邊找鬼。 笑死郁油,一個胖子當著我的面吹牛本股,可吹牛的內(nèi)容都是我干的攀痊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼拄显,長吁一口氣:“原來是場噩夢啊……” “哼苟径!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起躬审,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤棘街,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后承边,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遭殉,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年博助,在試婚紗的時候發(fā)現(xiàn)自己被綠了恩沽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡翔始,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出里伯,到底是詐尸還是另有隱情城瞎,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布疾瓮,位于F島的核電站脖镀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏狼电。R本人自食惡果不足惜蜒灰,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肩碟。 院中可真熱鬧强窖,春花似錦、人聲如沸削祈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽髓抑。三九已至咙崎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吨拍,已是汗流浹背褪猛。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留羹饰,地道東北人伊滋。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓碳却,卻偏偏與公主長得像,于是被迫代替她去往敵國和親新啼。 傳聞我的和親對象是個殘疾皇子追城,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容