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,这个大佬写的博客园