ActiveMQ 的线程池实质上也是 ThreadPoolExecutor,不过它的任务模型有自己的特点,我们先看一个例子:

public static void main(String[] args) throws InterruptedException {
// TaskRunnerFactory 的作用是创建线程池
TaskRunnerFactory factory = new TaskRunnerFactory();
factory.init();
// 创建 PooledTaskRunner
TaskRunner taskRunner = factory.createTaskRunner(new Task() {
// iterate 的返回值很重要,true表示继续,false表示停止
public boolean iterate() {
System.out.println("hello zhang");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
}, "zhang"); // 调用线程池的 execute(runnable)
taskRunner.wakeup(); LockSupport.park();
}

Task 接口真正处理业务逻辑。factory.createTaskRunner 的作用只是创建一个命名的 PooledTaskRunner。

PooledTaskRunner 封装了线程池 executor 和任务 runnable,只有在调用 PooledTaskRunner.wakeup() 时,才会调用 executor.execute(runnable),即真正执行任务。

以 Queue 类为例,它继承了 Task 接口,并且有自己的 taskRunner:

// org.apache.activemq.broker.region.Queue
public void initialize() throws Exception {
// 省略其他代码
// 创建queue的taskRunner
this.taskRunner = taskFactory.createTaskRunner(this, "Queue:" + destination.getPhysicalName());
}

queue 的 iterate:

//org.apache.activemq.broker.region.Queue
@Override
public boolean iterate() {
MDC.put("activemq.destination", getName());
boolean pageInMoreMessages = false;
synchronized (iteratingMutex) { // If optimize dispatch is on or this is a slave this method could be called recursively
// we set this state value to short-circuit wakeup in those cases to avoid that as it
// could lead to errors.
iterationRunning = true; // do early to allow dispatch of these waiting messages
synchronized (messagesWaitingForSpace) {
Iterator<Runnable> it = messagesWaitingForSpace.values().iterator();
while (it.hasNext()) {
if (!memoryUsage.isFull()) {
Runnable op = it.next();
it.remove();
op.run();
} else {
registerCallbackForNotFullNotification();
break;
}
}
} if (firstConsumer) {
firstConsumer = false;
try {
if (consumersBeforeDispatchStarts > 0) {
int timeout = 1000; // wait one second by default if
// consumer count isn't reached
if (timeBeforeDispatchStarts > 0) {
timeout = timeBeforeDispatchStarts;
}
if (consumersBeforeStartsLatch.await(timeout, TimeUnit.MILLISECONDS)) {
LOG.debug("{} consumers subscribed. Starting dispatch.", consumers.size());
} else {
LOG.debug("{} ms elapsed and {} consumers subscribed. Starting dispatch.", timeout, consumers.size());
}
}
if (timeBeforeDispatchStarts > 0 && consumersBeforeDispatchStarts <= 0) {
iteratingMutex.wait(timeBeforeDispatchStarts);
LOG.debug("{} ms elapsed. Starting dispatch.", timeBeforeDispatchStarts);
}
} catch (Exception e) {
LOG.error(e.toString());
}
} messagesLock.readLock().lock();
try{
pageInMoreMessages |= !messages.isEmpty();
} finally {
messagesLock.readLock().unlock();
} pagedInPendingDispatchLock.readLock().lock();
try {
pageInMoreMessages |= !pagedInPendingDispatch.isEmpty();
} finally {
pagedInPendingDispatchLock.readLock().unlock();
} // Perhaps we should page always into the pagedInPendingDispatch
// list if
// !messages.isEmpty(), and then if
// !pagedInPendingDispatch.isEmpty()
// then we do a dispatch.
boolean hasBrowsers = browserDispatches.size() > 0; if (pageInMoreMessages || hasBrowsers || !redeliveredWaitingDispatch.isEmpty()) {
try {
          //分发消息
pageInMessages(hasBrowsers);
} catch (Throwable e) {
LOG.error("Failed to page in more queue messages ", e);
}
} if (hasBrowsers) {
ArrayList<MessageReference> alreadyDispatchedMessages = null;
pagedInMessagesLock.readLock().lock();
try{
alreadyDispatchedMessages = new ArrayList<MessageReference>(pagedInMessages.values());
}finally {
pagedInMessagesLock.readLock().unlock();
} Iterator<BrowserDispatch> browsers = browserDispatches.iterator();
while (browsers.hasNext()) {
BrowserDispatch browserDispatch = browsers.next();
try {
MessageEvaluationContext msgContext = new NonCachedMessageEvaluationContext();
msgContext.setDestination(destination); QueueBrowserSubscription browser = browserDispatch.getBrowser(); LOG.debug("dispatch to browser: {}, already dispatched/paged count: {}", browser, alreadyDispatchedMessages.size());
boolean added = false;
for (MessageReference node : alreadyDispatchedMessages) {
if (!((QueueMessageReference)node).isAcked() && !browser.isDuplicate(node.getMessageId()) && !browser.atMax()) {
msgContext.setMessageReference(node);
if (browser.matches(node, msgContext)) {
browser.add(node);
added = true;
}
}
}
// are we done browsing? no new messages paged
if (!added || browser.atMax()) {
browser.decrementQueueRef();
browserDispatches.remove(browserDispatch);
}
} catch (Exception e) {
LOG.warn("exception on dispatch to browser: {}", browserDispatch.getBrowser(), e);
}
}
} if (pendingWakeups.get() > 0) {
pendingWakeups.decrementAndGet();
}
MDC.remove("activemq.destination");
iterationRunning = false; return pendingWakeups.get() > 0;
}
}

队列分发消息:

protected void pageInMessages(boolean force) throws Exception {
doDispatch(doPageInForDispatch(force, true));
}

ActiveMQ 的线程池的更多相关文章

  1. ActiveMQ使用线程池实现消息的生产与消费

    jar文件:spring3.1jar,以及 项目src路径下文件:config.properties 读取config.properties文件JAVA类: package com.lejob.lej ...

  2. JMS之——ActiveMQ时抛出的错误Could not connect to broker URL-使用线程池解决高并发连接

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/69046395 解决使用activemq时抛出的异常:javax.j ms.JMSE ...

  3. Java 线程池 8 大拒绝策略,面试必问!

    前言 谈到java的线程池最熟悉的莫过于ExecutorService接口了,jdk1.5新增的java.util.concurrent包下的这个api,大大的简化了多线程代码的开发.而不论你用Fix ...

  4. 基于线程池、消息队列和epoll模型实现并发服务器架构

    引言 并发是什么?企业在进行产品开发过程中为什么需要考虑这个问题?想象一下天猫的双11和京东的618活动,一秒的点击量就有几十万甚至上百万,这么多请求一下子涌入到服务器,服务器需要对这么多的请求逐个进 ...

  5. 并发编程-线程池&J.U.C

    8. 共享模型之工具 8.1 线程池 池化技术相比大家已经屡见不鲜了,线程池.数据库连接池.Http 连接池等等都是对这个思想的应用.池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率 ...

  6. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  7. C#多线程之线程池篇3

    在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...

  8. C#多线程之线程池篇2

    在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...

  9. C#多线程之线程池篇1

    在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...

随机推荐

  1. sql注入解析

    sql注入解析 sql注入解析(一)基本语法 sql注入解析(二)执行注入 sql注入解析(三)数据库类型 sql注入解析(四)避开过滤

  2. 登陆ArcGIS Server Manager时一直显示”请稍后……”

    登陆Server Manager时一直显示”请稍后……”新建完成ARcGIS ServerSite,设置用户名和密码.但是登陆时却发现一直处于等待状态,如下图: 更换为IE浏览器后发现,已经可以登陆并 ...

  3. ashx图片上传接收

    发送数据流方法 /// <summary> /// PostBinaryData /// </summary> /// <param name="url&quo ...

  4. red hat7 系统可以ping通ip地址但是不能ping通域名

    在red hat7中ifconfig后出现这样的情况,ens33是物理网卡,与eth0一样只是不同的名字.但是只能ping通ip地址不能ping通域名. 解决方法: 在文件 /etc/resolv.c ...

  5. 学习笔记44—Linux下安装freesurfer

    第一步:安装ubuntu (略过) 第二步:下载freesurfer:从freesurfer的官方网站上下载:http://surfer.nmr.mgh.harvard.edu/fswiki/Down ...

  6. 阿里云域名+github建立网站

    1.准备工作 ①购买一个阿里云域名,这里测试的域名为 www.cores.vip ②创建一个github账号 (注意:一个github账号只能建立一个username.github.io的网站,不能建 ...

  7. centos如何查看linux内核,版本号

    [root@localhost ~]# uname -a Linux localhost.localdomain -.el7.x86_64 # SMP Thu Nov :: UTC x86_64 x8 ...

  8. Codeforces 931F - Teodor is not a liar!

    931F - Teodor is not a liar! 思路: 最长上升子序列 先差分数组染色 如果存在一个点,被所有区间包含,那么这张图一定是山峰状,如下图: 那么只要分别从前和从后找一个最长非严 ...

  9. Python pickle使用

    2019-01-15 10:04:32 用于序列化的两个模块 json:用于字符串和Python数据类型间进行转换 pickle: 用于python特有的类型和python的数据类型间进行转换 jso ...

  10. WCF开发框架形成之旅--个人图片信息的上传保存

    WCF开发框架形成之旅--个人图片信息的上传保存 http://www.cnblogs.com/wuhuacong/archive/2011/12/23/2299614.html 一般在业务系统里面, ...