项目积累——Blockingqueue,ConcurrentLinkedQueue,Executors
背景
通过做以下一个小的接口系统gate,了解一下mina和java并发包里的东西。A系统为javaweb项目,B为C语言项目,gate是本篇须要完毕的系统。
需求
1. A为集群系统,并发较高,会批量发送给gate消息,而且接受gate返回的消息;
2. gate独立部署,将从A接受到的消息压入队列,与B建立连接后,将每条消息验证签名等工作后,发送给B,须要保证性能;
3. B负责处理消息,并返回处理结果,B为gate提供提供六个port,一个port可有三个长连接(须由gate发送心跳保持长连接,否则超时切断连接)。
实例
项目中用到了两个框架mina2.0.7和axis2。首先,gate须要接收从A发送过来的消息,为保证消息顺序性,压入队列中,为保证性能,将队列中的消息通过不同的连接发送至B,这让我们非常快就想到了多线程中生产者消费者的那张图,而且这是一个生产者,多个消费者,以下我们来看代码。
首先,gate作为服务端,要为A提供一个接口,使用axis2完毕了,关于webservice就不必多说,可看我前面的博客,配置例如以下:
<serviceGroup>
<service name="sendService" scope="application">
<description>
SendService
</description>
<messageReceivers>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/>
<messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
</messageReceivers>
<parameter name="ServiceClass">
cn.net.easyway.customer.SendService
</parameter>
</service>
</serviceGroup>
以下是服务实现类:
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import cn.net.easyway.nds.MsgConsumer;
import cn.net.easyway.nds.MsgProducer; /**
* 为用户管理系统提供服务接口
* @author yuanfubiao
*
*/
public class SendService { private static Log logger = LogFactory.getLog(SendService.class); private static int num = 0;
//消息队列
private static LinkedBlockingQueue<String> msgQueue = new LinkedBlockingQueue<String>();
//生产者线程池
private static ExecutorService executorProducer = Executors.newFixedThreadPool(20); //创建20个线程,应对并发较高的情况
//消费者线程池
private static ExecutorService executorCustomer = Executors.newFixedThreadPool(18); //和连接数相应 /**
* 放入消息
* @param list 消息列表
*/
public void putMsg(List<String> list){ //将消息放入队列
executorProducer.execute(new MsgProducer(msgQueue,list)); //取出消息:数据量大,启用全部线程
if(list.size() > 18){
for(int i=0;i<18;i++){
executorCustomer.execute(new MsgConsumer(msgQueue));
}
}else{
executorCustomer.execute(new MsgConsumer(msgQueue));
}
}
}
Java并发包为我们提供了非常多有用的多线程东西,因此没有必要自己去实现一个队列和线程池,如上面代码我们用到的队列是LinkedBlockingQueue,他为线程安全的堵塞队列,多线程操作时不必为了同步而担心,而且会将进出两边自己主动负载,他实现自BlockingQueue接口。
从jdk中能够看到实现BlockingQueue接口的还有ArrayBlockingQueue,DelayQueue,
LinkedBlockingDeque,LinkedBlockingQueue,LinkedTransferQueue,PriorityBlockingQueue,SynchronousQueue;此接口就是提供一个堵塞队列,从api中我们看到例如以下一张图:
Throwsexception:当队列已满,再次加入会抛出错误,取数据也是如此;
Specialvalue:加入或取出时会有一个返回值;
Blocks:是在队列已满或为空时,会一直堵塞;
Time Out:指堵塞到一定时间,线程退出;
当中,另一个并发队列也是作为生产者消费者的首选:ConcurrentLinkedQueue,它是非堵塞队列,肯定就不是出自Blockingqueue接口,而是出自AbstractQueue,因此也就没有put和take方法,使用这个并发队列须要有两点注意:第一,推断是否为空尽量使用isEmpty方法,不要用size(),有人測试过size方法非常耗费时间;第二就是线程问题,尽管ConcurrentLinkedQueue是线程安全的,可是仅仅负责原子性的,就是说当你操作queue.add()
or queue.poll的时候是安全的,当并发量较大时,你在使用queue.isEmpty时还不为空,但就在这空当有可能就运行poll操作,导致队列为空引起异常,可用例如以下代码:
synchronized(queue) {
if(!queue.isEmpty()) {
queue.poll();
}
}
在gate中,我定义了两个线程池,一个是生产者,还有一个是消费者:
//生产者线程池
private static ExecutorService executorProducer = Executors.newFixedThreadPool(20); //创建20个线程,应对并发较高的情况
//消费者线程池
private static ExecutorService executorCustomer = Executors.newFixedThreadPool(18);
Executors提供了一个工厂方法,用来创建线程池,返回的线程池都实现了ExecutorService接口,能够创建例如以下线程池:
newCachedThreadPool():创建一个可缓存的线程池,调用execute将重用曾经构造的线程,假设如今线程没有可用的,则创建一个新线程加入到池中,终止并从缓存中溢出那些已有60秒未被使用的线程;
newFixedThreadPool(intnThreads):创建固定的线程;
newScheduledThreadPool(intcorePoolSize):创建一个支持定时及周期性的任务运行的线程池;
newSingleThreadExecutor():创建一个单线程的Executor;
启动线程,有两个方法,一个是execute(),还有一个是submit(),后者是有返回值的,会将运行的结果Future返回,关于Future可移步这里。
以下就是生产者和消费者代码:
生产者:
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue; /**
* 向队列加入消息
* @author yuanfubiao
*
*/
public class MsgProducer implements Runnable { private LinkedBlockingQueue<String> msgQueue; private List<String> message; public MsgProducer(LinkedBlockingQueue<String> queue,List<String> msg) {
this.msgQueue = queue;
this.message = msg;
} @Override
public void run() {
Iterator<String> iter = message.iterator();
while(iter.hasNext()){
String msg = iter.next();
try {
msgQueue.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消费者:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue; import nds.framework.security.NDSMD5; import org.apache.commons.codec.binary.Hex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.session.IoSession; /**
* 从消息队列取出消息
* @author yuanfubiao
*
*/
public class MsgConsumer implements Runnable{ private static Log logger = LogFactory.getLog(MsgConsumer.class);
private LinkedBlockingQueue<String> msgQueue; public MsgConsumer(LinkedBlockingQueue<String> queue) {
this.msgQueue = queue;
} @Override
public void run() {
while(!msgQueue.isEmpty()){ String msg = null;
try {
msg = msgQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
} if(null == msg){
return;
} //增加时间
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
String now = format.format(new Date());
String prefix = msg.substring(0, 19);
String suffix = msg.substring(33, msg.length());
String packet = prefix.trim() + now.trim() + suffix.trim(); //签名部分忽略
//TODO
String newStr = packet // 签名 + signature.toUpperCase().trim();
//关于mina,可见我下篇文章
IoSession session = SessionPool.getSession(newStr.substring(13, 15));
logger.info("发送数据:" + newStr);
session.write(newStr); try {
Thread.sleep(1000); //等待一秒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
源代码下载:http://download.csdn.net/detail/stubbornpotatoes/7438435
项目积累——Blockingqueue,ConcurrentLinkedQueue,Executors的更多相关文章
- (转载) android快速搭建项目积累
android快速搭建项目积累 2016-04-05 20:07 519人阅读 评论(0) 收藏 举报 分类: android优化(8) Rx技术(5) 版权声明:本文为博主原创文章,未经博主 ...
- 【angular5项目积累总结】遇到的一些问题以及解决办法
1.项目中字符串特别是\r\n,替换成br之后,在页面换行无法生效? 答:绑定元素 innerHTML. <div class="panel-body" [innerHTML ...
- 项目积累(三)CSS
公司不是专门做网站的,偶尔会接到客户让修改前端,有时候和让头疼,自己浏览器兼容问题处理不好. 慢慢积累吧. 先贴出来一些前端代码吧,如下: <div class="test" ...
- 项目积累html标签
今天遇到一个不太常用都标签,网上以后慢慢记下项目中用到都东西. 1.<em> 标签 告诉浏览器把其中的文本表示为强调的内容.对于所有浏览器来说,这意味着要把这段文字用斜体来显示. 在文本中 ...
- 项目积累——JAVA知识积累
调用天气: <iframe src="http://www.thinkpage.cn/weather/weather.aspx?uid=&c=CHXX0008&l=zh ...
- 项目积累——js应用
//解决由前台向后台传值中文乱码的问题 encodeURI($("#xmjhbgFile").val())//前台JS中数据加码 String fjmc = java.net.UR ...
- 【angular5项目积累总结】消息订阅服务
code import { Injectable } from '@angular/core'; import { Subject } from 'rxjs/Subject'; @Injectable ...
- 项目积累demo-01
1 搭建Spring-Boot项目 在这里我使用intellij新建spring boot工程: 点击next; 输入Group以及artifact之后.点击next.之后点击web.接着finish ...
- 【项目积累】对JSON数据的处理
[项目简述] 接触.NET项目非常长一段时间了,前台用的都是MVC框架.不知道大家是否想过一个问题.我们是怎样将数据显示到前台的,换句话说,MVC能够识别怎么样的数据形式?答案非常ea ...
随机推荐
- U盘开发之GPIF Master模式
在U盘开发过程中,一个人从头做到尾,经常遇到一些莫名其妙的问题,只有到官网论坛发帖.折腾困扰我最久的,就是U盘的读写性能问题了,不采用GPIF的方式,single读只有几百K,single写只有几十K ...
- Google map v3 using simple tool file google.map.util.js v 1.2
更新添加日志:在1.1的基础上添加marker的文字显示.测距工具. /** * GOOGLE地图开发使用工具 * @author BOONYACHENGDU@GMAIL.COM * @date 20 ...
- 【HDU 5572 An Easy Physics Problem】计算几何基础
2015上海区域赛现场赛第5题. 题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5572 题意:在平面上,已知圆(O, R),点B.A(均在圆外),向量 ...
- hdu 2222 Keywords_ac自动机模板
题意:给你n个单词,再给你一串字符,求在字符中有多少个单词出现过 #include <iostream> #include<cstdio> #include<cstrin ...
- 如何使用TestFlight进行App构建版本测试(转)
在日常的开发当中,当一个项目在开发过程中或者完成准备上线,都需要我们进行真机测试,否则不可能开发完了就直接扔到了App,等上线了再下载看看,这都是不可能的.那么说到真机测试,大家肯定会想到弄一个99美 ...
- JDK自带工具jps,jstat,jmap,jconsole使用
jps 与ps命令类似: ps -ef|grep java 用来显示本地的java进程,查看本地执行着几个java应用,并显示进程号. [root@SE43 ~]# jps //仅仅显示进程号 238 ...
- ios5和ios6横竖屏支持及ipad和iphone设备的判断
ios5和ios6横竖屏支持及ipad和iphone设备的判断 判断是ipad还是iphone设备.此定义在PayViewControllerDemo-Prefix.pch 定义如下: #define ...
- OS Kernel Parameter.semopm
安装Oracle11g内核参数semopm未校验通过,点击Fix&Check Again后,会提示执行修改脚本,在/tmp/CVU_11.2.0.1.0_oracle下,找到并执行该脚本run ...
- Oracle触发器Trigger2行级
create table trigger_t2( id int, name ), age int ); /* --创建一个before update的触发器-控制每一行,行级 --只有行级的才会有:n ...
- oracle查询表信息
oracle查询表信息(索引,外键,列等) oracle中查询表的信息,包括表名,字段名,字段类型,主键,外键唯一性约束信息,索引信息查询SQL如下: 1.查询出所有的用户表 select * fro ...