ArrayBlockingQueue的使用案例:

ArrayBlockingQueue的介绍:

ArrayBlockingQueue,顾名思义:基于数组的阻塞队列。数组是要指定长度的,所以使用ArrayBlockingQueue时必须指定长度,也就是它是一个有界队列。

它实现了BlockingQueue接口,有着队列、集合以及阻塞队列的所有方法,

他有三个构造方法:

并没有无参构造,所以必须要初始化长度,不让他变成一个无边界的数据队列,可能会存在内存过大的问题

内部实现了ReentrantLock锁,所以线程是安全的,

使用场景,异步队列发送邮件:

首先封装mail对象进queue队列:

public class Email implements Serializable {
    private static final long serialVersionUID = 1L;
    //必填参数
    private String[] email;//接收方邮件
    private String subject;//主题
    private String content;//邮件内容
    //选填
    private String template;//模板
    private HashMap<String, String> kvMap;// 自定义参数
    
    
    
    public Email() {
        super();
    }
    
    public Email(String[] email, String subject, String content, String template,
            HashMap<String, String> kvMap) {
        super();
        this.email = email;
        this.subject = subject;
        this.content = content;
        this.template = template;
        this.kvMap = kvMap;
    }


    public String[] getEmail() {
        return email;
    }
    public void setEmail(String[] email) {
        this.email = email;
    }
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public String getTemplate() {
        return template;
    }
    public void setTemplate(String template) {
        this.template = template;
    }
    public HashMap<String, String> getKvMap() {
        return kvMap;
    }
    public void setKvMap(HashMap<String, String> kvMap) {
        this.kvMap = kvMap;
    }
}

然后写一个MailQueue:

package com.itstyle.mail.common.queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import com.itstyle.mail.common.model.Email;
/**

public class MailQueue {
     //队列大小
    static final int QUEUE_MAX_SIZE   = 1000;

    //static BlockingQueue<Email> blockingQueue = new LinkedBlockingQueue<Email>(QUEUE_MAX_SIZE);

    static ArrayBlockingQueue<Email> blockingQueue=new ArrayBlockingQueue<Email>(100);
    
    /**
     * 私有的默认构造子,保证外界无法直接实例化
     */
    private MailQueue(){};
    /**
     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
     * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
     */
    private static class SingletonHolder{
        /**
         * 静态初始化器,由JVM来保证线程安全
         */
        private  static MailQueue queue = new MailQueue();
    }
    //单例队列
    public static MailQueue getMailQueue(){
        return SingletonHolder.queue;
    }
    //生产入队
    public  void  produce(Email mail) throws InterruptedException {
        blockingQueue.put(mail);
    }
    //消费出队
    public  Email consume() throws InterruptedException {
        return blockingQueue.take();
    }
    // 获取队列大小
    public int size() {
        return blockingQueue.size();
    }
}

里面包括了消费和创建的方法:

 //生产入队
    public  void  produce(Email mail) throws InterruptedException {
        blockingQueue.put(mail);
    }
    //消费出队
    public  Email consume() throws InterruptedException {
        return blockingQueue.take();
    }

使用静态内部类的方法,保证单利模式

消费队列:

package com.itstyle.mail.common.queue;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.itstyle.mail.common.model.Email;
import com.itstyle.mail.service.IMailService;

@Component
public class ConsumeMailQueue {
    private static final Logger logger = LoggerFactory.getLogger(ConsumeMailQueue.class);
    @Autowired
    IMailService mailService;
    
    @PostConstruct
    public void startThread() {
        ExecutorService e = Executors.newFixedThreadPool(2);// 两个大小的固定线程池
        e.submit(new PollMail(mailService));
        e.submit(new PollMail(mailService));
    }

    class PollMail implements Runnable {
        IMailService mailService;

        public PollMail(IMailService mailService) {
            this.mailService = mailService;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    Email mail = MailQueue.getMailQueue().consume();
                    if (mail != null) {
                        logger.info("剩余邮件总数:{}",MailQueue.getMailQueue().size());
                        mailService.send(mail);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @PreDestroy
    public void stopThread() {
        logger.info("destroy");
    }
}

这种从线程池获取消费线程来执行,这个里面是一个多线程环境,为什么可以保证线程安全呢,是由于ArrayBlokcingQueue实现了reentranlock来实现的,

 

 在这里将需要发送邮件的信息添加到队列中去.

如果需要判断是否满了,就需要使用offer方法,不是使用reminingkey方法:

可以参看下面文字:https://www.xttblog.com/?p=3686,这个大佬写的博客园

 

posted @ 2019-05-14 17:24  菩提树下的丁春秋  阅读(3744)  评论(0编辑  收藏  举报