定时发送消息--延迟队列

本文介绍了Java中实现定时发送消息的三种方式:使用Timer和TimerTask创建定时器,利用BlockingQueue实现阻塞队列,以及通过DelayQueue创建延迟队列。详细讲解了各个组件的工作原理、核心方法,并提供了相关示例代码。
摘要由CSDN通过智能技术生成

定时发送消息–延迟队列

一、定时器(Timer)

定时计划任务功能在Java中主要使用的就是Timer对象,它在内部使用多线程的方式进行处理,所以它和多线程技术还是有非常大的关联的。在JDK中Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某一个任务,用TimerTask类封装任务。

通过Timer和Timetask,我们可以实现定时启动某个线程。

java.util.Timer
  在这种实现方式中,Timer类作用是类似闹钟的功能,也就是定时或者每隔一定时间触发一次线程。其实,Timer类本身实现的就是一个线程,只是这个线程是用来实现调用其它线程的。
java.util.TimerTask
  TimerTask类是一个抽象类,该类实现了Runnable接口,所以该类具备多线程的能力。
Demo

根据不同的传入参数可以实现,固定时间后执行,间隔固定时间执行,传入Calendar对象可在指定时间执行。

public class TestTimer {
   
    public static void main(String[] args) {
   
        Timer t1 = new Timer();//定义计时器;
        MyTask task1 = new MyTask();//定义任务;
        t1.schedule(task1,3000);  //3秒后执行;
        //t1.schedule(task1,5000,1000);//5秒以后每隔1秒执行一次!
        //GregorianCalendar calendar1 = new GregorianCalendar(2010,0,5,14,36,57); 
        //t1.schedule(task1,calendar1.getTime()); //指定时间定时执行; 
    }
}
 
class MyTask extends TimerTask {
   //自定义线程类继承TimerTask类;
    public void run() {
   
        for(int i=0;i<10;i++){
   
            System.out.println("任务1:"+i);
        }
    }
}

定时器的使用流程很简单:

(1)第一步:创建一个Timer。

(2)第二步:创建一个TimerTask

(3)第三步:使用Timer执行TimerTask

涉及到的类的类图:
在这里插入图片描述

二、阻塞队列(BlockingQueue)

​ 所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足,被挂起的线程又会自动被唤醒

​ 阻塞队列(在concurrent包内),是一个不仅实现了队列所具有的基本功能,同时还在多线程环境下自动管理了线程间的等待与唤醒功能,使之能够兼顾效率与线程安全。

​ 多线程环境中,通过队列可以很容易实现数据共享,比如经典的“生产者”和“消费者”模型中,通过队列可以很便利地实现两者之间的数据共享。假设我们有若干生产者线程,另外又有若干个消费者线程。如果生产者线程需要把准备好的数据共享给消费者线程,利用队列的方式来传递数据,就可以很方便地解决他们之间的数据共享问题。但如果生产者和消费者在某个时间段内,万一发生数据处理速度不匹配的情况呢?理想情况下,如果生产者产出数据的速度大于消费者消费的速度,并且当生产出来的数据累积到一定程度的时候,那么生产者必须暂停等待一下(阻塞生产者线程),以便等待消费者线程把累积的数据处理完毕,反之亦然。

BlockingQueue的核心方法:

1.放入数据

(1)offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false.(本方法不阻塞当前执行方法

的线程);      
  (2)offer(E o, long timeout, TimeUnit unit):可以设定等待的时间,如果在指定的时间内,还不能往队列中加入BlockingQueue,则返回失败。

(3)put(anObject):把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续.

2. 获取数据

(1)poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null;

(2)poll(long timeout, TimeUnit unit):从BlockingQueue取出一个队首的对象,如果在指定时间内,队列一旦有数据可取,则立即返回队列中的数据。否则知道时间

超时还没有数据可取,返回失败。

(3)take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入;

(4)drainTo():一次性从BlockingQueue获取所有可用的数据对象(还可以指定获取数据的个数),通过该方法,可以提升获取数据效率;不需要多次分批加锁或释放锁。

BlockingQueue成员
在这里插入图片描述

生产者消费者Demo

生产者

public class Producer implements Runnable{
   


    private volatile boolean  isRunning = true;//是否在运行标志
    private BlockingQueue queue;//阻塞队列
    private static AtomicInteger count = new AtomicInteger();//自动更新的值
    private static final int DEFAULT_RANGE_FOR_SLEEP = 1000;

    //构造函数
    public Producer(BlockingQueue queue) {
   
        this.queue = queue;
    }

    public void run() {
   
        String data = null;
        Random r = new Random();

        System.out.println("启动生产者线程!");
        try {
   
            while (isRunning) {
   
                System.out.println("正在生产数据...");
                Thread.sleep(r.nextInt(DEFAULT_RANGE_FOR_SLEEP));//取0~DEFAULT_RANGE_FOR_SLEEP值的一个随机数

                data = "data:" + count.incrementAndGet();//以原子方式将count当前值加1
                System.out.println("将数据:" + data + "放入队列...");
                if (!queue.offer(data, 2, TimeUnit.SECONDS)) {
   //设定的等待时间为2s,如果超过2s还没加进去返回true
                    System.out.println("放入数据失败:" + data);
                }else{
   
                    System.out.println("队列长度:" + queue.size());
                }
            }
        } catch (InterruptedException e) {
   
            e.pri
RabbitMQ延迟队列可以用于定时发送消息。在RabbitMQ中,延迟队列是通过设置消息的过期时间来实现的。在发送消息时,可以指定消息的过期时间,当消息过期时,RabbitMQ会将消息发送到指定的队列。 以下是设置RabbitMQ延迟队列定时发送消息的步骤: 1. 创建一个普通队列,用于存储延迟消息。 2. 创建一个交换机,用于将延迟消息发送延迟队列中。 3. 创建一个延迟队列,将其绑定到交换机上。 4. 发送消息时,设置消息的过期时间,并将消息发送到交换机。 5. 当消息过期时,RabbitMQ会将消息发送延迟队列中。 6. 消费延迟队列中的消息。 以下是使用Java代码设置RabbitMQ延迟队列定时发送消息的示例: ``` ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); // 创建普通队列 channel.queueDeclare("my-queue", false, false, false, null); // 创建交换机 channel.exchangeDeclare("my-exchange", "direct"); // 创建延迟队列 Map<String, Object> args = new HashMap<>(); args.put("x-message-ttl", 10000); // 设置延迟时间为10秒 args.put("x-dead-letter-exchange", "my-exchange"); // 设置延迟消息发送到的交换机 channel.queueDeclare("my-delay-queue", false, false, false, args); // 将延迟队列绑定到交换机上 channel.queueBind("my-delay-queue", "my-exchange", ""); // 发送消息并设置过期时间 String message = "Hello, RabbitMQ!"; AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder() .expiration("10000") // 设置过期时间为10秒 .build(); channel.basicPublish("my-exchange", "", properties, message.getBytes()); // 消费延迟队列中的消息 channel.basicConsume("my-delay-queue", true, new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String message = new String(body, "UTF-8"); System.out.println("Received message: " + message); } }); ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值