欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?延時(shí)隊(duì)列及簡(jiǎn)單使用方式詳解

 更新時(shí)間:2023年08月10日 11:42:24   作者:假女吖?  
這篇文章主要介紹了Java延時(shí)隊(duì)列簡(jiǎn)單使用方式,通過本文學(xué)習(xí)知道延時(shí)隊(duì)列是什么可以用來干什么,本文通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

Java 延時(shí)隊(duì)列,簡(jiǎn)單使用方式

前言:首先我們要知道延時(shí)隊(duì)列是什么?可以用來干什么?

是什么?

看名稱 隊(duì)列 可想而知 先進(jìn)先出 的一個(gè)集合。但我們的延時(shí)隊(duì)列并沒有完全的遵循這個(gè)理念。

DelayQueue 內(nèi)部其實(shí)是基于我們的 優(yōu)先隊(duì)列 來實(shí)現(xiàn)的,也就是元素的先后順序是按元素的 Comparable 接口提供的順序來 出隊(duì) 的。

DelayQueue 內(nèi)部的元素必須是 Delayed 的的實(shí)現(xiàn)類 而 Delayed 的父接口是 Comparable<Delayed> 。

Delayed 接口中需要我們實(shí)現(xiàn)一個(gè) long getDelay(TimeUnit unit); 元素的剩余時(shí)間 TTL

干什么?

  • 定時(shí)任務(wù)。
  • 重試(5秒重試)。
  • 延時(shí)通知。

都可以基于延時(shí)隊(duì)列來實(shí)現(xiàn)。

開發(fā)中遇到一個(gè)這樣的需求。

需要一個(gè)集合來維護(hù)熱點(diǎn)數(shù)據(jù),但這個(gè)熱點(diǎn)數(shù)據(jù)是有時(shí)效性的,我們?cè)谌ゲ樵兊臅r(shí)候先要判斷下這個(gè)熱點(diǎn)數(shù)據(jù)不存在,或者不在有效期內(nèi)的。才能走剩下的邏輯。

當(dāng)然這個(gè)需求聽起來并不復(fù)雜。

我們自己實(shí)現(xiàn)的話。

是不是需要一個(gè)有順序的集合?

是不是還每個(gè)元素都有一個(gè)有效期?

是不是還得保證元素出隊(duì)的順序?

如果說還有另外一個(gè)地方需要復(fù)用,我們是不是還得再寫一套這樣的邏輯。

所以,我們可以直接使用 DelayQueue 來實(shí)現(xiàn)這個(gè)需求,他天生就能保證我們的集合是有順序的,并且保證過期的元素不在集合內(nèi)。

簡(jiǎn)單使用

延時(shí)對(duì)象

@Data
static class SimpleDelayed<T> implements Delayed {
    /**
     * 對(duì)象創(chuàng)建時(shí)間
     */
    @JsonIgnore
    private final Date createDate;
    /**
     * 延時(shí)數(shù)(單位毫秒)
     */
    private long delayCount;
    private T data;
    public SimpleDelayed(T data, long delayCount) {
        this.data = data;
        this.delayCount = delayCount;
        this.createDate = new Date();
    }
    @Override
    public long getDelay(TimeUnit unit) {
        long diff = this.createDate.getTime() + this.delayCount - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }
    @Override
    public int compareTo(Delayed delayed) {
        return Long.compare(this.getDelay(TimeUnit.MILLISECONDS),delayed.getDelay(TimeUnit.MILLISECONDS));
    }
}

注意: compareTo 提供的順序必須要與 getDelay 否則會(huì)出現(xiàn)元素過期了但是在隊(duì)列中。因?yàn)?DelayQueue 內(nèi)部維護(hù)的是一個(gè) 優(yōu)先隊(duì)列 。所以必須保證這兩順序是一致的。所以這里的 compareTo 直接比較了這兩的 剩余過期數(shù) 越小的越先出隊(duì)。反之會(huì)出現(xiàn), 延時(shí)時(shí)間 已過,但是沒有出隊(duì)。 compareTo 靠前,但是過期數(shù)未過的數(shù)卡著。

延時(shí)隊(duì)列工具類

@Slf4j
public class SimpleDelayQueueUtils {
   /**
     * 1.定義了一個(gè)延時(shí)隊(duì)列 隊(duì)列中元素是我們的SimpleDelayed
     */
    private final static DelayQueue<SimpleDelayed> SIMPLE_DELAYED_DELAY_QUEUE = new DelayQueue<>();
    static{
      	// 2.聲明一個(gè)異步線程
        CompletableFuture.runAsync(() -> {
          	// 3.通過自旋去出隊(duì)已過期的元素
            for (;;) {
                try {
					// 4.take() 對(duì)頭元素出隊(duì)。
                    log.info("元素已過期{}",SIMPLE_DELAYED_DELAY_QUEUE.take().getData());
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        // 單個(gè)線程的線程池,為了不占用fork-join線程池
        }, Executors.newSingleThreadExecutor());
    }
    public static void add(SimpleDelayed... delayeds) {
        SIMPLE_DELAYED_DELAY_QUEUE.addAll(Arrays.asList(delayeds));
    }
  	// 測(cè)試
    public static void main(String[] args) {
        SimpleDelayed<String> nonceDelayed = new SimpleDelayQueueUtils.SimpleDelayed<>("111",5001);
        SimpleDelayed<String> nonceDelayed1 = new SimpleDelayQueueUtils.SimpleDelayed<>("222", 4500);
        SimpleDelayQueueUtils.add(nonceDelayed,nonceDelayed1);
    }
}

輸出

23:35:00.693 [pool-1-thread-1] INFO com.mfyuan.chenapioperation.util.SimpleDelayQueueUtils - 元素已過期222
23:35:01.189 [pool-1-thread-1] INFO com.mfyuan.chenapioperation.util.SimpleDelayQueueUtils - 元素已過期111

思考

這里的 data 元素是可以靈活替換的,因?yàn)槲疫@里的需求是涉及到隊(duì)列中的元素是否過期。所以這些就已經(jīng)足夠了。

但是當(dāng)我們把 data ,替換成 Runable 再把出隊(duì)的的元素通過線程池的方式去調(diào)用則就實(shí)現(xiàn)了 定時(shí)任務(wù) 重試 也可以當(dāng)做 定時(shí)任務(wù) 來理解,就把當(dāng)單做一個(gè)任務(wù),如果任務(wù)執(zhí)行失敗了或者出現(xiàn)異常了,那么我們重新講元素放入延時(shí)隊(duì)列中即可。

后話

Redis來實(shí)現(xiàn)我這個(gè)功能,雖然可以實(shí)現(xiàn)但是有些地方實(shí)現(xiàn)的邏輯也是不簡(jiǎn)單。更別說引入 redis 的開發(fā)成本,殺??不需要??刀。

Redis zset 是可以保證集合的元素有順序的, zset ttl 是指這個(gè) zset 整體的過期時(shí)間。(不確定,)

到此這篇關(guān)于Java 延時(shí)隊(duì)列,簡(jiǎn)單使用方式的文章就介紹到這了,更多相關(guān)java延時(shí)隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論