Cola de retraso implementada basada en DelayQueue

Basado en el artículo sobre la implementación de la cola de retraso en Java , esta vez implementaremos principalmente DelayQueuela cola de retraso basada en la implementación.

Pasos para utilizar DelayQueuela cola de retraso implementada:

  1. Defina una clase que herede Delayed, defina sus propiedades y anule los compareTodos getDelaymétodos
  2. Crear una Delayqueuecola para crear
  3. Crear un productor que agregue información a la cola.
  4. Crear un consumidor para recuperar información de la cola para consumo.

La siguiente es una demostración simple:

definir una clase de elemento


import lombok.Data;

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


@Data
public class DelayTesk implements Delayed {
    
    

    //标签Id
    private String uid;

    //到期时间
    private Long timestamp;

    //延时信息
    private String data;

    @Override
    public long getDelay(TimeUnit unit) {
    
    
        long delayTime = timestamp - System.currentTimeMillis();
        //将时间转换成毫秒(这边可转可不转,影响不大)
        return unit.convert(delayTime, TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
    
    
        //针对任务的延时时间长短进行排序,把延时时间最短的放在前面
        long differenceTime = this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);
        return (int)differenceTime;
    }
}

Definir una cola de retraso


import java.util.concurrent.DelayQueue;


public class DelayTaskQueue {
    
    
    /**
     * 这边使用单例模式进行创建,保证全局队列的唯一性
     * 我这边使用的是双检索,双校验模式
     */
    private volatile static DelayQueue<DelayTesk> delayTaskQueue;

    private DelayTaskQueue(){
    
    }

    public static DelayQueue<DelayTesk> getDelayTaskQueue() {
    
    
        if (delayTaskQueue == null) {
    
    
            synchronized (DelayTaskQueue.class) {
    
    
                if (delayTaskQueue == null) {
    
    
                    delayTaskQueue = new DelayQueue<>();
                }
            }
        }
        return delayTaskQueue;
    }
}

Crear un productor de cola de retraso

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.DelayQueue;

//消息生产者
@Slf4j
public class DelayTeskQueueProducer {
    
    

    /**
     *  往延时队列中插入数据
     * @param uid
     * @param time
     * @param data
     */
    public static void setDelayQueue(String uid, Long time, String data) {
    
    
        //创建队列
        DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();
        //创建任务
        DelayTesk delayTesk = new DelayTesk();
        delayTesk.setUid(uid);
        delayTesk.setTimestamp(time);
        delayTesk.setData(data);
        log.info("====================消息入队:{}===============", uid);
        boolean res = delayTaskQueue.offer(delayTesk);
        if (res) {
    
    
            log.info("====================消息入队成功:{}===============", uid);
        } else {
    
    
            //如果消息入队失败这边可以写一个失败的回调函数
            //例如将失败的消息存入数据库,写个定时任务对消息进行重写投递……
            log.info("====================消息入队失败:{}===============", uid);
        }
    }
}

Definir un consumidor de una cola de retraso

import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.DelayQueue;

@Slf4j
public class DelayTeskQueueConsumer {
    
    

    public static void main(String[] args) {
    
    
        for (int i = 0; i < 10 ; i++) {
    
    
            DelayTeskQueueProducer.setDelayQueue(IdUtil.fastUUID(), System.currentTimeMillis() + i * 1000, "hello world" + i);
        }
        int index = 0;
        DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();
        while (index < 10) {
    
    

            try {
    
    
                DelayTesk delayTesk = delayTaskQueue.take();
                System.out.println(delayTesk.getData());
            } catch (InterruptedException e) {
    
    
                log.error("延时队列消费异常:{}", e.getMessage());
            }
        }
    }
}

Como resultado,
se imprime una línea de datos cada segundo en la consola de control.
Insertar descripción de la imagen aquí

En este punto, nuestra demostración casi ha terminado, pero algunos estudiantes pueden preguntar, ¿no está su consumidor escrito en el método mian y debe llamarlo manualmente cada vez que consume? Esto se logra usando la función de suspensión directamente conmigo. ¿Cuál es la diferencia entre cola de retraso y cola de retraso?

No se preocupe, esto es solo una demostración. Si necesita usarlo en su proyecto, puede escribir un oyente para monitorear la cola de retraso en tiempo real. Aquí solo hablaré de
3 tipos por el momento.

Temporizador

Utilice el temporizador para configurar la frecuencia para recibir DelayTaskQueueel mensaje

import com.study.project.delay.DelayTaskQueue;
import com.study.project.delay.DelayTesk;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.DelayQueue;

/**
 *  添加@Configuration  注解,自动注入实例对象,并由springboot 启动 定时器,执行任务。
 */

@Configuration
@Slf4j
public class DelayTeskQueueTimer {
    
    

    @Bean
    public void DelayTeskQueueTimer() {
    
    
        log.info("====================监听开始====================");
        final Timer timer = new Timer();
        DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();
        timer.schedule(new TimerTask() {
    
    
            @Override
            public void run() {
    
    
                try {
    
    
                    DelayTesk delayTesk = delayTaskQueue.take();
                    System.out.println(delayTesk.getData());
                } catch (Exception e) {
    
    
                    log.error("延时队列消费异常:{}", e.getMessage());
                }
            }
         //第一次执行是在当前时间的一秒之后,之后每隔一秒钟执行一次
        },1000, 1000);
    }
}

corredor de línea de comando

import com.study.project.delay.DelayTaskQueue;
import com.study.project.delay.DelayTesk;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.DelayQueue;
/**
 * Spring Boot应用程序在启动后,程序从容器中遍历实现了CommandLineRunner接口的实例并运行它们的run方法
 */
@Slf4j
@Configuration
public class DelayTeskQueueTimerCommandLineRunner implements CommandLineRunner {
    
    

    @Override
    public void run(String... args) {
    
    
        log.info("====================CommandLineRunner监听开始====================");
        DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();
        new Thread(() ->{
    
    
            while (true) {
    
    
                try {
    
    
                    DelayTesk delayTesk = delayTaskQueue.take();
                    System.out.println(delayTesk.getData());
                } catch (Exception e) {
    
    
                    log.error("延时队列消费异常:{}", e.getMessage());
                }
            }
        }).start();
    }
}

Oyente de aplicaciones

Este método, al igual que el método, monitorea ConmandlineRunnerla aplicación Spring Boot después de que se inicia.DelayQueue

import com.study.project.delay.DelayTaskQueue;
import com.study.project.delay.DelayTesk;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.concurrent.DelayQueue;

@Slf4j
@Configuration
public class DelayTeskQueueApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
    
    
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
    
    
        log.info("====================ApplicationListener监听开始====================");
        DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();
        new Thread(() -> {
    
    
            while (true) {
    
    
                try {
    
    
                    DelayTesk delayTesk = delayTaskQueue.take();
                    System.out.println(delayTesk.getData());
                } catch (Exception e) {
    
    
                    log.error("延时队列消费异常:{}", e.getMessage());
                }
            }
        }).start();
    }
}

Por supuesto, en realidad existen muchos métodos de monitoreo, pero al implementar colas, los estudiantes no deben pensar que es suficiente implementarlas, sino que deben pensar en cómo garantizar la persistencia de los datos y garantizar que no se pierdan.

Supongo que te gusta

Origin blog.csdn.net/qq_43649799/article/details/129461731
Recomendado
Clasificación