阻塞队列

BlockingQueue阻塞队列

通常我们在使用阻塞队列中还根据长度判断阻塞量,当阻塞达到一定数据量我们会打印出告警日志,然后查看是什么原因造成,并进行处理,减少阻塞量。

ArrayBlockingQueue

内部是基于一个定长数组生成的队列,还同时存储开头和尾部的位置。生成者和消费者是公用一个锁的,所以不可以并行进行。初始化是需要制定大小长度。

LinkedBlockingQueue

内部是基于一个链表生成的队列。生产者和消费者是各自分别使用单独的锁的,可以并行处理。初始化可以不指定长度,如果不指定长度,会生成一个近似无线大的长度,integer.MAX_VALUE,不建议,建议指定长度。

PriorityBlockingQueue

PriorityBlockingQueue是一个具有优先级的阻塞队列。优先级的顺序可以自己定义。PriorityBlockingQueue阻塞队列中的对象必须实现Comparable<>接口。

实现Comparable接口,需要实例化compareTo方法。该方法定义了优先级的顺序。默认的优先级的顺序是从小到大。

DelayQueue

DelayQueue 是一个具有延迟的阻塞队列。DelayQueue队列中的对象必须实现Delay接口。

实现Delay接口,需要实例化两个方法:compareTo(T t)和getDelay(TimeUtil util)。

  • compareTo方法用于指定优先级排序。
  • getDelay用于得到延迟时间。

在队列中的对象不一定需要直接实现Delay接口。可以通过中间对象,中间对象实现Delay接口,该中间对象支持泛型的方式。

应用场景

  1. 部省上报自定义清除消息机制。

    生成活跃告警时,随机生成一个3天内的清除告警。将该告警对象和随机清除时间放入延迟队列中,以便到底清除时间时,触发清除告警。用于解决该活跃告警没有清除告警情况下告警清除的情况。

2.

样例代码如下:

实体类:

package com.foundation.student.model;

import java.util.Date;

/**
 * @author: eastcom
 * @desc:
 **/
public class MSEvent {

    private Long recordId;

    private Long objectId;

    private String objectName;

    private Date saveTime;

    private Date clearTime;

    public Long getRecordId() {
        return recordId;
    }

    public void setRecordId(Long recordId) {
        this.recordId=recordId;
    }

    public Long getObjectId() {
        return objectId;
    }

    public void setObjectId(Long objectId) {
        this.objectId=objectId;
    }

    public String getObjectName() {
        return objectName;
    }

    public void setObjectName(String objectName) {
        this.objectName=objectName;
    }

    public Date getSaveTime() {
        return saveTime;
    }

    public void setSaveTime(Date saveTime) {
        this.saveTime=saveTime;
    }

    public Date getClearTime() {
        return clearTime;
    }

    public void setClearTime(Date clearTime) {
        this.clearTime=clearTime;
    }

    @Override
    public String toString() {
        return "MSEvent{" + "recordId=" + recordId + ", objectId=" + objectId + ", objectName='" + objectName + '\'' + ", saveTime=" + saveTime + ", clearTime=" + clearTime + '}';
    }
}

中间对象:

package com.foundation.student.model;

import java.util.Date;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: eastcom
 * @desc:
 **/
public class DelayItem<T> implements Delayed {

    private T item;

    private long time;

    /**
     * 使用AtomicInteger计数,用于处理时间延迟一致的情况下,进行优先级排序。
     */
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    private final long sequenceNumber;

    public DelayItem(T item, Date time) {
        this.item=item;
        this.time= time.getTime();
        this.sequenceNumber = atomicInteger.getAndIncrement();
    }

    /**
     * 计算当前时间到执行时间之间还有多长时间
     * @param unit
     * @return
     */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(time - (new Date()).getTime(),
                TimeUnit.NANOSECONDS);
    }

    /**
     * 比较优先级大小,一般正数表示顺序,负数表示倒序。
     * @param delayed
     * @return
     */
    @Override
    public int compareTo(Delayed delayed) {
       if(delayed instanceof  DelayItem){
           DelayItem item = (DelayItem) delayed;
           long diff = this.time - item.time;

           if(diff > 0){
               return 1;
           }

           if(diff < 0 ){
               return -1;
           }

           if(this.sequenceNumber > item.sequenceNumber){
               return 1;
           }

           if(this.sequenceNumber < item.sequenceNumber){
               return -1;
           }
       }
       long diff = this.getDelay(TimeUnit.NANOSECONDS) - delayed.getDelay(TimeUnit.NANOSECONDS);
       return diff > 1 ? 1 : -1;
    }

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item=item;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time=time;
    }

    @Override
    public String toString() {
        return "DelayItem{" + "item=" + item.toString() + ", time=" + time + ", atomicInteger=" + atomicInteger + ", sequenceNumber=" + sequenceNumber + '}';
    }
}

逻辑处理类:

package com.foundation.student.queue;

import com.foundation.student.model.DelayItem;
import com.foundation.student.model.MSEvent;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;

/**
 * @author: eastcom
 * @desc: Delay队列需要实现Delay接口,需要自己实现compareTo、getDelay两个方法。
 * 可以自己封装一个对象,DelayItem<T>泛型的方式将需要的对象注入。
 **/
public class DelayBlockingQueueTest {
    private DelayQueue<DelayItem<MSEvent>> queue = new DelayQueue<>();

    public static void main(String[] args){
        try{
            DelayBlockingQueueTest test = new DelayBlockingQueueTest();
            test.test();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }

    private void test(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        ThreadPoolExecutor executorService =(ThreadPoolExecutor) applicationContext.getBean("taskExector");
        executorService.submit(new DelayBlockingQueueTest.DelayBlockingQueueObject());
        executorService.submit(new DelayBlockingQueueTest.DelayBlockingTakeObject());
    }

    class DelayBlockingTakeObject implements Runnable{

        @Override
        public void run(){
            while(true){
                try {
                    DelayItem<MSEvent> delayItem2 = queue.take();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    System.out.println(sdf.format(new Date())+" :  "+delayItem2.toString());
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                }finally {
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                }
            }
        }
    }

    class DelayBlockingQueueObject implements Runnable {

        @Override
        public void run() {
            long i=0;
            while (true){
                MSEvent event = new MSEvent();
                event.setRecordId(i);
                event.setObjectId(i);
                event.setSaveTime(new Date());
                Date clearTime = new Date();
                clearTime.setTime(clearTime.getTime()+ThreadLocalRandom.current().nextLong(1000,5000));
                event.setClearTime(clearTime);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                System.out.println(sdf.format(event.getSaveTime()));
                System.out.println(sdf.format(clearTime));
                System.out.println("put object is "+event.toString());
                DelayItem<MSEvent> delayItem = new DelayItem<>(event,clearTime);
                queue.put(delayItem);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                i++;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值