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接口,该中间对象支持泛型的方式。
应用场景
部省上报自定义清除消息机制。
生成活跃告警时,随机生成一个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++;
}
}
}
}