java併發程式設計工具類JUC第三篇:DelayQueue延時佇列

字母哥部落格發表於2021-06-01

DelayQueue 是BlockingQueue介面的實現類,它根據"延時時間"來確定佇列內的元素的處理優先順序(即根據佇列元素的“延時時間”進行排序)。另一層含義是隻有那些超過“延時時間”的元素才能從佇列裡面被拿出來進行處理。

  • DelayQueue 佇列將阻止其元素物件從佇列中被取出,直到達到為元素物件設定的延遲時間。DelayQueue 在佇列的頭部儲存最近過期的元素,如果佇列內沒有元素過期,使用poll()方法獲取佇列內的元素將會返回null。
  • DelayQueue 類及其迭代器實現了CollectionIterator介面的所有可選方法,但迭代器方法iterator()不能保證以特定的順序遍歷DelayQueue的元素。

  • DelayQueue 不接收null元素,DelayQueue 只接受那些實現了java.util.concurrent.Delayed介面的物件,並將其放入佇列內。DelayQueue 通過呼叫元素物件的getDelay(TimeUnit) 方法獲取該元素剩餘的“延遲時間”。getDelay()的 TimeUnit時間單位是一個列舉型別 : DAYS(天), HOURS(小時), MINUTES(分鐘), SECONDS(秒), MILLISECONDS(毫秒), MICROSECONDS(微妙), NANOSECONDS(納秒)
public interface Delayed extends Comparable{
   long getDelay(TimeUnit unit);
}

下面我們就寫一個java Class實現Delayed 介面,只有實現了Delayed 介面的類物件才能放入DelayQueue。因為Delayed介面繼承自Comparable介面,所以我們必須實現getDelay方法和compareTo方法。

class DelayObject implements Delayed {
    private String name; 
    private long time;   //延時時間

    public DelayObject(String name, long delayTime) { 
      this.name = name; 
      this.time = System.currentTimeMillis() + delayTime; 
    } 

   @Override
   public long getDelay(TimeUnit unit) {
      long diff = time - System.currentTimeMillis(); 
      return unit.convert(diff, TimeUnit.MILLISECONDS); 
   } 

   @Override
   public int compareTo(Delayed obj) { 
      if (this.time < ((DelayObject)obj).time) { 
         return -1; 
      } 
      if (this.time > ((DelayObject)obj).time) { 
         return 1; 
      } 
      return 0; 
   } 

   @Override
   public String toString() {
     Date date = new Date(time);
     SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

     return "\nDelayObject:{"
       + "name=" + name
       + ", time=" +  sd.format(date)
       + "}";
   } 
} 

測試延時佇列DelayQueue的使用效果

public class DelayQueueTest {

  @Test
  void testDelayObject() throws InterruptedException {

    //例項化一個DelayQueue
    BlockingQueue<DelayObject> DQ = new DelayQueue<>();

    //向DelayQueue新增四個元素物件,注意延時時間不同
    DQ.add(new DelayObject("A", 1000 * 10));  //延時10秒
    DQ.add(new DelayObject("B", 4000 * 10));  //延時40秒
    DQ.add(new DelayObject("C", 3000 * 10));  //延時30秒
    DQ.add(new DelayObject("D", 2000 * 10));  //延時20秒

    SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    //將物件從DelayQueue取出,注意取出的順序與延時時間有關
    System.out.println( DQ.take());  //取出A
    System.out.println( DQ.take());  //取出D
    System.out.println( DQ.take());  //取出C
    System.out.println( DQ.take());  //取出B

  }
}

從下面的列印結果及上文的程式碼可以看出

  • 佇列中元素放入的順序是A、B、C、D,取出的順序是A、D、C、B,這是因為佇列中的元素按照延時時間進行了排序。
  • 另外我們可以看到,每隔10秒才可以從佇列中取出一個元素,這是因為只有超過“延時時間”的元素才能從佇列裡面被拿出來。而我們設定的延時時間是10s、20s、30s、40s。
DelayObject:{name=A, time=2021-03-23 14:14:20}

DelayObject:{name=D, time=2021-03-23 14:14:30}

DelayObject:{name=C, time=2021-03-23 14:14:40}

DelayObject:{name=B, time=2021-03-23 14:14:50}

歡迎關注我的部落格,裡面有很多精品合集

  • 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格

覺得對您有幫助的話,幫我點贊、分享!您的支援是我不竭的創作動力! 。另外,筆者最近一段時間輸出瞭如下的精品內容,期待您的關注。

相關文章