基于数组阻塞队列 ArrayBlockingQueue 的一个队列工具类
java语言基于ArrayBlockingQueue 开发的一个根据特定前缀和后缀的队列。每天自动循环生成。
1.定义队列基类 Cookie
package com.bytter.util.queue; import java.util.Date; import java.util.concurrent.ArrayBlockingQueue; public class Cookie { private ArrayBlockingQueue<String> queue; private int cursor = 1; private Date date = new Date(); private int maxPoolQueue = 500; private int mixPoolQueue = 100; public Cookie(int maxPoolQueue,int mixPoolQueue,Date date){ this.maxPoolQueue=maxPoolQueue; this.mixPoolQueue=mixPoolQueue; this.date=date; this.queue = new ArrayBlockingQueue<String>(this.maxPoolQueue,true); } public Cookie(int maxPoolQueue,int mixPoolQueue,Date date, int cursor){ this.maxPoolQueue = maxPoolQueue; this.mixPoolQueue = mixPoolQueue; this.date=date; this.cursor=cursor; this.queue = new ArrayBlockingQueue<String>(this.maxPoolQueue,true); } public ArrayBlockingQueue<String> getQueue() { return queue; } public Cookie setQueue(ArrayBlockingQueue<String> queue) { this.queue = queue; return this; } public int getCursor() { return cursor; } public Cookie setCursor(int cursor) { this.cursor = cursor; return this; } public Date getDate() { return date; } public Cookie setDate(Date date) { this.date = date; return this; } public int getMaxPoolQueue() { return maxPoolQueue; } public Cookie setMaxPoolQueue(int maxPoolQueue) { this.maxPoolQueue = maxPoolQueue; return this; } public int getMixPoolQueue() { return mixPoolQueue; } public Cookie setMixPoolQueue(int mixPoolQueue) { this.mixPoolQueue = mixPoolQueue; return this; } }
2.QueueUtil 队列工具类,用于获取队列中的值(主要是获取付款的单号==)
package com.bytter.util.queue; import java.util.Date; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.bytter.framework.persistence.dao.IBaseDAO; import com.bytter.util.AppContextUtil; import com.bytter.util.DateUtil; /** * * @author * May 6, 2019 10:35:39 AM * @version */ public class QueueUtil{ private static Logger log = LogManager.getLogger(QueueUtil.class); protected static IBaseDAO baseDao = null; private static ConcurrentHashMap<String, Cookie> queueMap = new ConcurrentHashMap<String, Cookie>(); private static class SingletonClassInstance{ private static final QueueUtil instance=new QueueUtil(); } private QueueUtil(){} public static QueueUtil getInstance(){ return SingletonClassInstance.instance; } /** * 调用事例: QueueUtil.getInstance().getSequence(SequenceEnum.BIS_EXC) * @param sequenceEnum * @return * @throws InterruptedException */ @SuppressWarnings("unchecked") public String getSequence(SequenceEnum sequenceEnum) throws InterruptedException{ String value = ""; String key = sequenceEnum.getTableName()+"_"+sequenceEnum.getFieldName(); Cookie cookie = queueMap.get(key); value = cookie.getQueue().take(); String returnValue = sequenceEnum.getPrefix()+DateUtil.dateToStr(sequenceEnum.getDateFormat(), new Date()); for (int i = 0; i < sequenceEnum.getSequenceLength()-value.length(); i++) { returnValue += "0"; } returnValue += value; log.info("取出的单号:"+returnValue); return returnValue; } public void initQueue() { putAllMap(); Thread thread = new Produce(queueMap); thread.setName("QueueUtil_Produce"); thread.start(); } private static void putAllMap() { queueMap.clear(); int curor = 1; log.info("-----开始加载队列 -------"); for (SequenceEnum sequenceEnum : SequenceEnum.values()){ String key = sequenceEnum.getTableName()+"_"+sequenceEnum.getFieldName(); //同一天但是系统重启或者宕机的情况时,游标重置为1.此时需要查询表中最大的值并且置游标值+1 String sql="SELECT MAX("+sequenceEnum.getFieldName()+") FROM "+sequenceEnum.getTableName()+" WHERE "+sequenceEnum.getFieldName()+" LIKE '"+sequenceEnum.getPrefix()+"%'"; List list = baseDao.search_sql(null, sql, "", "", null); if(list != null && list.size() >0 && list.get(0) != null){ String no = list.get(0).toString(); //单号,自增。 String count = no.substring(no.length()-sequenceEnum.getSequenceLength()); String date = no.replaceAll(count, "").replaceAll(sequenceEnum.getPrefix(), ""); /*if(date.equals(DateUtil.dateToStr(sequenceEnum.getDateFormat(), new Date()))){ curor = Integer.parseInt(count) + 1; }*/ } log.info("加载队列 :table=="+sequenceEnum.getTableName()+" field=="+sequenceEnum.getFieldName()+" 游标=="+curor); queueMap.put(key, new Cookie(sequenceEnum.getMaxSeqSize(),sequenceEnum.getMinSeqSize(),new Date(),curor)); } log.info("-----队列加载完毕 -------"); } static{ baseDao = AppContextUtil.getBean("baseDao"); //第一次调用时开启队列 //initQueue(); } }
3.生产者线程类
package com.bytter.util.queue; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentHashMap; import com.bytter.util.DateUtil; public class Produce extends Thread{ private ConcurrentHashMap<String, Cookie> queueMap; public Produce(ConcurrentHashMap<String, Cookie> queueMap){ this.queueMap=queueMap; } public void run(){ ArrayBlockingQueue<String> queue; int mixSize; int curor; Cookie cookie; Date date; Map.Entry<String,Cookie> entry; Iterator<Map.Entry<String,Cookie>> iteratorMap; while (true) { iteratorMap = queueMap.entrySet().iterator(); while (iteratorMap.hasNext()){ entry = iteratorMap.next(); cookie = entry.getValue(); queue = cookie.getQueue(); mixSize = cookie.getMixPoolQueue(); curor = cookie.getCursor(); date = cookie.getDate(); //新的一天,游标开始重置 if(!DateUtil.dateToStr("yyyy-MM-dd", new Date()).equals(DateUtil.dateToStr("yyyy-MM-dd", date))){ curor = 1; queue.clear(); date = new Date(); System.out.println("重置游标时间===="+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); } //offer 在填满后返回false if(queue.size() < mixSize){ while (queue.offer(curor + "")) { curor++; } } cookie.setQueue(queue).setCursor(curor).setDate(date); queueMap.put(entry.getKey(),cookie); } } } }
4.自定义的生成单号的规则枚举类
package com.bytter.util.queue; public enum SequenceEnum{ /** * 付款指令编码 yyMMdd000001 * @return */ BIS_EXC("",6, "BIS_EXC", "VOUCHER_NO", "yyMMdd",500,100), /** * 付款单号 * @return */ PAYMENT_BILL_NO("P",7, "T_BIS_PAYMENT_INFO", "BILL_CODE", "yyMMddHHmmss",500,100), ; /** * 流水号前缀 */ private String prefix; /** * 流水号数字部分长度 */ private Integer sequenceLength; /** * 业务表名 */ private String tableName; /** * 业务表中的字段名 */ private String fieldName; /** * 日期格式化模板 */ private String dateFormat; /** * 队列最大的长度 */ private int maxSeqSize; /** * 队列最小长度 */ private int minSeqSize; /** * @param prefix 流水号前缀 * @param sequenceLength 流水号自增长长度 * @param tableName 表名 * @param fieldName 字段名 * @param dateFormat 日期格式化模板 */ SequenceEnum(String prefix, Integer sequenceLength, String tableName, String fieldName,String dateFormat,int maxSeqSize,int minSeqSize) { this.prefix = prefix; this.sequenceLength = sequenceLength; this.tableName = tableName; this.fieldName = fieldName; this.dateFormat = dateFormat; this.maxSeqSize = maxSeqSize; this.minSeqSize = minSeqSize; } /** * @param prefix 流水号前缀 * @param sequenceLength 流水号自增长长度 * @param tableName 表名 * @param fieldName 字段名 * @param dateFormat 日期格式化模板 */ SequenceEnum(Integer sequenceLength, String tableName, String fieldName,String dateFormat) { this.sequenceLength = sequenceLength; this.tableName = tableName; this.fieldName = fieldName; this.dateFormat = dateFormat; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public Integer getSequenceLength() { return sequenceLength; } public void setSequenceLength(Integer sequenceLength) { this.sequenceLength = sequenceLength; } public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } public String getFieldName() { return fieldName; } public void setFieldName(String fieldName) { this.fieldName = fieldName; } public String getDateFormat() { return dateFormat; } public void setDateFormat(String dateFormat) { this.dateFormat = dateFormat; } public int getMaxSeqSize() { return maxSeqSize; } public void setMaxSeqSize(int maxSeqSize) { this.maxSeqSize = maxSeqSize; } public int getMinSeqSize() { return minSeqSize; } public void setMinSeqSize(int minSeqSize) { this.minSeqSize = minSeqSize; } }
5.测试相关类
1> 消费者线程
package com.bytter.util.queue; public class implements Runnable{ public void run(){ try { for (int i = 0; i < 200; i++) { Thread.sleep(Long.valueOf((long) (Math.random()*10*300))); // System.out.println(Thread.currentThread().getName()); System.out.println(Thread.currentThread().getName()+"==="+SequenceUtilTest.getInstance().getSequence(SequenceEnum.BIS_EXC)); } } catch (Exception e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } }
2>测试main 方法
package com.bytter.util.queue; public class tests { public static void main(String[] args) throws InterruptedException { new Thread(new Consume()).start(); new Thread(new Consume()).start(); new Thread(new Consume()).start(); new Thread(new Consume()).start(); new Thread(new Consume()).start(); // new Thread(new Consume()).start(); // new Thread(new Consume()).start(); // new Thread(new Consume()).start(); // new Thread(new Consume()).start(); // new Thread(new Consume()).start(); } }