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. Pandas 基础(3) - 生成 Dataframe 的几种方式

    这一节想总结一下 生成 Dataframe 的几种方式: CSV Excel python dictionary List of tuples List of dictionary 下面分别一一介绍具 ...

  2. Ubuntu 编译安装 Xdebug

    安装xdebug 1.下载 https://xdebug.org/download.php 找到PHP5.6对应的版本 https://xdebug.org/files/xdebug-2.5.5.tg ...

  3. 设计模式(四) Factory Pattern工厂模式

    核心: 实例化对象,实现创建者和调用者的分离 简单工厂模式 工厂方法模式 抽象工厂模式 面对对象设计的基本原则: ocp(open closed principle) 开闭原则:一个软件的实体应当对拓 ...

  4. L1-044. 稳赢

    这种题不是考思维,就是考你细心程度还有基础知识的,代码如下: #include <iostream> #include <string> using namespace std ...

  5. ie67的冷知识

    1. _display:inline;是什么意思 只有ie6认识带下划线的,一般这种写法是用来消除ie6对margin双倍的bug的,比如你写margin-left:10px;那么ie6下显示的是20 ...

  6. Spring学习笔记(入门)

    1.基本看了一下,spring就是利用这个框架帮助我们实例化对象的工具.首先我们需要引入jar包,pom.xml如下: <project xmlns="http://maven.apa ...

  7. (转+整理)Nandflash存储

    ----------------------------------------------------------------------文章1--------------------------- ...

  8. Redis入门指南之二(安装及配置)

    本节主要内容 1. 前言2. redis安装3. 启动和停止Redis 1. 前言 安装Redis需要知道自己需要哪个版本,有针对性的安装,比如如果需要redis GEO这个地理集合的特性,那么red ...

  9. 20165327 2017-2018-2 《Java程序设计》第2周学习总结

    20165327 2017-2018-2 <Java程序设计>第2周学习总结 内容:教材第2.3章 内容小结: (一)标识符由字母.下划线.美元符号和数字组成, 并且第一个字符不能是数字字 ...

  10. WPF——UI布局

    1.规划整体布局(规划界面结构)——>这样就可以划分出若干区域(区域的控件通常是一些容器控件) 2.针对 上面的 “若干区域” ,制作每个区域的一级用户控件(然后,将该用户控件放入对应的区域中) ...