- 浏览: 199235 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (67)
- 私人笔记 (43)
- 转载日志 (5)
- 学习笔记 (11)
- Java (8)
- Google Guice (1)
- ImageIo (2)
- mina (3)
- nio (1)
- epoll (1)
- ubuntu (2)
- dia (1)
- vysper (2)
- Guice (1)
- Jetty (1)
- Continuation (1)
- long polling (1)
- Bootstrap (1)
- lbs (1)
- Tomcat (1)
- JVM (1)
- GC (1)
- 图片处理 (2)
- 清除图片锯齿 (0)
- 业余折腾 (0)
- dpi (1)
- eclipse (1)
- Netty (3)
- android (1)
- javamail (1)
- Protobuf (1)
最新评论
-
sankby:
终于找到这个说明了,netty权威指南上关于readInter ...
Netty源码笔记I - 关于『注册SelectionKey#OP_ACCEPT』 -
liuchao150:
写个filter, 那struts2里的上传,File获取不到 ...
upload.parseRequest(request) 结果为null的一个恶心处理法 -
星璇凌:
这样改后,action中的set方法不起作用了,前台传到后台的 ...
upload.parseRequest(request) 结果为null的一个恶心处理法 -
l578682879:
于是,我自己实现一个servlet.Filter,并且把它的f ...
upload.parseRequest(request) 结果为null的一个恶心处理法 -
phperbar:
不错,效果还可以
用html5做了一个打气球小游戏
简要说明
1、基于javamail所做的批量发邮件小程序,SingleSender是普通发送,ThreadSender是多线程发送,MysqlSender是从数据库获取数据再调用ThreadSender来发送。
2、为啥写这个小程序呢?没啥特别的,只因最近想起thinking in java里面介绍的CountDownLatch类,为了练手多线程相关的技术而写了这个小程序,整个程序于我而言核心在ThreadSender里面的CountDownLatch。
3、jar依赖情况
1) 必须:activation.jar, mail.jar, commons-logging.jar, log4j-xx.jar, zTool-xx.jar(我写的另外一些小工具类,源码在 https://z-tool.googlecode.com/svn/trunk/zTool)
2) 可能需要:mysql-connector-java-xx.jar,velocity-xx-dep.jar
(注:上面版本号用xx代替了,依据实际情况找个合适的版本即可)
下面贴出SingleSender和ThreadSender的源码。详细源码在 https://github.com/auzll/zBatchSender
1、基于javamail所做的批量发邮件小程序,SingleSender是普通发送,ThreadSender是多线程发送,MysqlSender是从数据库获取数据再调用ThreadSender来发送。
2、为啥写这个小程序呢?没啥特别的,只因最近想起thinking in java里面介绍的CountDownLatch类,为了练手多线程相关的技术而写了这个小程序,整个程序于我而言核心在ThreadSender里面的CountDownLatch。
3、jar依赖情况
1) 必须:activation.jar, mail.jar, commons-logging.jar, log4j-xx.jar, zTool-xx.jar(我写的另外一些小工具类,源码在 https://z-tool.googlecode.com/svn/trunk/zTool)
2) 可能需要:mysql-connector-java-xx.jar,velocity-xx-dep.jar
(注:上面版本号用xx代替了,依据实际情况找个合适的版本即可)
下面贴出SingleSender和ThreadSender的源码。详细源码在 https://github.com/auzll/zBatchSender
public final class SingleSender extends AbstractSender { private static final Log LOG = LogFactory.getLog(SingleSender.class); /** * 发送一批邮件 * @param entities 邮件实体列表 */ public final List<MailEntity> send(List<MailEntity> entities) { int entitiesSize = null != entities ? entities.size() : 0; if (LOG.isInfoEnabled()) { LOG.info("method:send,entitiesSize:" + entitiesSize + ",senderParam:[" + this.toSimpleLog() + "]" + ",thread:" + Thread.currentThread().toString()); } if (entitiesSize < 1) { return entities; } /** TODO Test code begin */ // 模拟测试一下好了,不做实际发信 for (MailEntity entity : entities) { try { TimeUnit.SECONDS.sleep(new Random().nextInt(3)); } catch (InterruptedException e) { } if (LOG.isInfoEnabled()) { LOG.info("method:send,result:success,entity:[" + entity.toSimpleLog() + "],thread:" + Thread.currentThread().toString()); } } if (true) return entities; /** TODO Test code end */ Transport transport = null; Session session = null; int curTimes = 0; Properties sessionProperties = newProperties(); for (MailEntity entity : entities) { try { if (null == transport || !transport.isConnected() || curTimes == transportUsingTimes) { if (null != transport && transport.isConnected()) { transport.close(); } session = Session.getInstance(sessionProperties); transport = session.getTransport(new URLName("smtp", smtpHost, smtpPort, null, from.getAddress(), password)); // 获取新的transport curTimes = 0; transport.connect(); if (LOG.isDebugEnabled()) { LOG.debug("method:send,desc:transport connect,thread:" + Thread.currentThread().toString()); } } MimeMessage message = new MimeMessage(session); if (null != from) { message.setFrom(from); } if (null != entity.getTo()) { message.addRecipient(RecipientType.TO, entity.getTo()); } if (null != entity.getCcTo()) { message.addRecipient(RecipientType.CC, entity.getCcTo()); } if (null != entity.getBccTo()) { message.addRecipient(RecipientType.BCC, entity.getBccTo()); } if (null != subject) { message.setSubject(subject); } if (null != entity.getContent()) { message.setText(entity.getContent(), charset); } else if (null != content) { message.setText(content, charset); } // 发送邮件 transport.sendMessage(message, message.getAllRecipients()); // 成功发送 entity.setSuccess(true); if (LOG.isInfoEnabled()) { LOG.info("method:send,result:success,entity:[" + entity.toSimpleLog() + "],thread:" + Thread.currentThread().toString()); } } catch (Exception e) { // 发送失败 entity.setSuccess(false); if (LOG.isDebugEnabled()) { LOG.debug("method:send,result:fail,entity:[" + entity.toSimpleLog() + "],thread:" + Thread.currentThread().toString(), e); } else { LOG.info("method:send,result:fail,entity:[" + entity.toSimpleLog() + "],thread:" + Thread.currentThread().toString() + ",e:" + e.getMessage()); } } finally { curTimes++; } } if (null != transport && transport.isConnected()) { try { transport.close(); } catch (Exception e) { LOG.info("method:send,desc:close transport,thread:" + Thread.currentThread().toString() , e); } } return entities; } /** * 发送一封邮件 * @param entity 邮件实体 */ public final MailEntity send(MailEntity entity) { List<MailEntity> entities = new ArrayList<MailEntity>(); entities.add(entity); send(entities); return entity; } private Properties newProperties() { String address = from.getAddress(); String host = address; int atIndex = address.indexOf('@'); if (-1 != atIndex) { host = address.substring(atIndex + 1); } Properties props = new Properties(); props.put("mail.smtp.localhost", host); props.put("mail.from", address); props.put("mail.debug", mailDebug); if (null != password) { props.put("mail.smtp.auth", true); } return props; } }
public final class ThreadSender extends AbstractSender { private static final Log LOG = LogFactory.getLog(ThreadSender.class); private class Worker implements Runnable { private CountDownLatch latch; private List<MailEntity> entities; public Worker(CountDownLatch latch, List<MailEntity> entities) { this.latch = latch; this.entities = entities; } public void run() { new SingleSender() .charset(charset) .smtpHost(smtpHost) .smtpPort(smtpPort) .transportUsingTimes(transportUsingTimes) .from(from) .password(password) .subject(subject) .content(content) .send(entities); if (LOG.isDebugEnabled()) { LOG.debug("method:Worker$run,desc:latch count down,thread:" + Thread.currentThread().toString()); } latch.countDown(); } } /** 默认的最大线程数量:Runtime.getRuntime().availableProcessors() * 2 */ public static final int DEFAULT_THREAD_SIZE = Runtime.getRuntime().availableProcessors() * 2; /** 每个线程单次任务默认的发送邮件量 */ public static final int DEFAULT_TASK_OF_EACH_THREAD = 10; /** 线程数量 */ private int threadSize = DEFAULT_THREAD_SIZE; /** 每个线程单次任务最大发送邮件量 */ private int taskOfEachThread = DEFAULT_TASK_OF_EACH_THREAD; private ExecutorService executorService; /** 是否在发送邮件后关闭executorService,若executorService由外界传入就不关闭,否则关闭 */ private boolean shutdownExecutor = false; public ThreadSender() { this(Executors.newCachedThreadPool()); this.shutdownExecutor = true; } public ThreadSender(ExecutorService executorService) { this.executorService = executorService; } /** * 发送一批邮件 * @param entities 邮件实体列表 */ public final List<MailEntity> send(List<MailEntity> entities) { int entitiesSize = null != entities ? entities.size() : 0; if (LOG.isInfoEnabled()) { LOG.info("method:send,entitiesSize:" + entitiesSize + ",thread:" + Thread.currentThread().toString()); } if (entitiesSize < 1) { return entities; } int maxTask = threadSize * taskOfEachThread; if (entities.size() > maxTask) { throw new BatchSendException("Too much task, max is " + maxTask + ", current is " + entities.size()); } int i = 0, toIndex = 0, len = entities.size(); int count = len / taskOfEachThread; if (len % taskOfEachThread > 0) { count++; } CountDownLatch latch = new CountDownLatch(count); int realCount = 0; while (i < len) { if (LOG.isDebugEnabled()) { LOG.debug("method:send,desc:split task,taskIndex:" + realCount); } toIndex = i + taskOfEachThread; if (toIndex > len) { toIndex = len; } executorService.execute(new Worker(latch, entities.subList(i, toIndex))); i = toIndex; realCount++; } if (count != realCount) { throw new BatchSendException("Unexpected error[count != realCount], count is " + count + ", realCount is " + realCount); } try { if (LOG.isDebugEnabled()) { LOG.debug("method:send,desc:begin await,thread:" + Thread.currentThread().toString()); } latch.await(); if (LOG.isDebugEnabled()) { LOG.debug("method:send,desc:finish await,thread:" + Thread.currentThread().toString()); } } catch (InterruptedException e) { throw new BatchSendException(e); } if (shutdownExecutor) { if (LOG.isDebugEnabled()) { LOG.debug("method:send,desc:try shutdown executorService,thread:" + Thread.currentThread().toString()); } executorService.shutdownNow(); } return entities; } public ThreadSender taskOfEachThread(int taskOfEachThread) { this.taskOfEachThread = taskOfEachThread; return this; } public ThreadSender threadSize(int threadSize) { this.threadSize = threadSize; return this; } }
发表评论
-
还是在csdn写博客吧!
2018-06-16 23:43 352博客,还是要尽量写写的。 最早是javaeye(iteye) ... -
准备继续写博客,放在github pages
2018-01-11 15:58 57很久不写博客,年终回忆总结时,像是工作学习断了层,太多有价值的 ... -
[简略记录]使用Netty过程遇到的一个傻X错误——异常处理
2014-07-31 23:20 5996最近基于netty写了点服务器端的程序,算是第一次比较正式的使 ... -
入职五周年
2014-07-13 11:56 2920简单的记一记吧。 今天是我正式入职五周年的日子!2009年大 ... -
初试python des
2013-11-08 13:38 900初试python des,使用了pyDes: from ... -
再整理一段javamail的发信代码
2013-10-15 15:26 697Properties p = new Pro ... -
我遇到tomcat 7 full gc频繁的问题
2013-07-11 22:45 7976近日开始关注JVM的问题,先用jstat -gcut ... -
【练习代码】试用百度BAE和练手jetty continuation的副成品 —— 一个简陋的WEB版LBS聊天应用
2013-07-04 22:49 1388最近写了个测试小应 ... -
【练习代码】写了基于java nio的RepeatServer -- by auzll
2013-05-21 11:53 1648昨天在翻看mina源码时,突然想起我貌似还 ... -
【源码学习】Mina笔记 (一)
2013-05-21 00:36 1488因最近准备 ... -
试玩github pages
2013-05-09 23:55 982哈哈,试玩了一下github pages,还 ... -
试试html5的拖拉事件和FileReader
2013-05-09 15:59 1815<html> <head> ... -
java格式化GMT时间
2013-05-09 12:54 1110FastDateFormat.getInstance(&quo ... -
maven 若干学习笔记
2012-12-27 12:50 8151、从项目路径设置dependency <depen ... -
REST 相关资源
2012-12-26 10:00 877REST 论文的中文版:http://www.redsaga. ... -
我的常用链接
2012-10-17 10:27 867The Java EE 6 Tutorial: http:// ... -
JAVA用ImageIO处理JPG图片
2012-10-15 15:36 1722Image srcImage = ImageIO.re ... -
用java试试在Mysql环境中注入sql
2012-10-09 08:06 1150一般的说,在java环境中,使用java.sql.St ... -
ant打包之排除特定文件
2012-06-20 19:38 4288<copy todir="${build.di ... -
[BUG排查日记]2012-06-04
2012-06-04 20:57 956最近更新系统,在 ...
相关推荐
mybaits 多线程 实现数据批量插入 (运用CountDownLatch实现闭锁) 1、mybatis批处理 2、数据分批量查询 3、数据分批量插入
主要介绍了如何使用CountDownLatch同步java多线程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
利用 CountDownLatch 类实现线程同步,而不用回调机制。详见我的博文 http://blog.csdn.net/kroclin/article/details/37956949
NULL 博文链接:https://cpjsjxy.iteye.com/blog/2272451
主要为大家详细介绍了使用CountDownLatch等待多线程全部执行完成,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
主要介绍了Java中CountDownLatch进行多线程同步详解及实例代码的相关资料,需要的朋友可以参考下
主要介绍了JAVA多线程CountDownLatch的使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
在Java中和ReadWriteLock.ReadLock一样,CountDownLatch的本质也是一个"共享锁",这里我们就来详解Java多线程编程中CountDownLatch阻塞线程的方法:
多线程相关的(具体包括Lock synchronized Join ThreadLocal Executors CountDownLatch等)一些demo。
主要介绍了Java多线程编程之CountDownLatch同步工具使用实例,需要的朋友可以参考下
内容概要:最新2023年Java高并发多线程后端面试题整理, 包含线程池,并发集合,volatile,CountDownLatch,Semaphore,Phaser,AQS,ReentrantLock,ReentrantLock等等问题, 用简洁明了的语言,通俗易懂地阐述了高...
看完《think in java》多线程章节,自己写的多线程文档,还结合了其他的相关网络资料。 线程 一. 线程池 1)为什么要使用线程池 2 2)一个具有线程池的工作队列 3 3)使用线程池的风险: 4 4)有效使用线程池的原则 5...
importExcel 方法接收一个 Excel 文件对象、批大小 batchSize 和线程数 threadCount 作为参数。首先,使用 ExcelReader 对象读取 Excel 文件,并计算出总行数和分片大小和数量;然后,创建一个固定数量的线程池,...
《java并发编程》中CountDownLatch和CyclicBarrier用法实例大全,几乎包含了所有重要的用法
目录 CountDownLatch是什么? CountDownLatch如何工作? 在实时系统中的应用场景 应用范例 常见的面试题 代码样例
本篇文章主要介绍了Java中多线程同步类 CountDownLatch的相关知识,具有很好的参考价值。下面跟着小编一起来看下吧
CountDownLatch 和 CyclicBarrier 为线程同步的辅助工具,通过它可以做到使一条线程一直阻塞等待,直到其他线程完成其所处理的任务。
JUC(Java Util Concurrent)是Java中用于并发编程的工具包,提供了一组接口和类,用于处理多线程和并发操作。JUC提供了一些常用的并发编程模式和工具,如线程池、并发集合、原子操作等。 JUC的主要特点包括: ...
CountDownLatch可以实现一个线程等待多个线程、多个线程等待一个线程、多个线程等待多个线程(这里不涉及)。 我们首先来看看怎么实现一个线程等待多个线程吧。 工厂中,对产品需要进行质检,5个工人进行检查,所有...
1)CountDownLatch(同步倒数计数器:等待多线程(或者多步骤)完成) 2)CyclicBarrier(循环屏障:同步屏障) 3)Semaphore(信号量:控制并发进程数) 主要参考资料:java并发编程的艺术、Java并发——...