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. mac删除python

    删除Python框架 sudo rm -rf /Library/Frameworks/Python.framework/Versions/x.x 删除Python本程序 sudo rm -rf &qu ...

  2. border:none和border:0的区别

    C:当定义border:none时,表示无边框样式,浏览器并不会对边框进行渲染,也就没有实际的宽度:  D:定义边框时,除了设置宽度外,还必须设置边框的样式才能显示出来.     border:0;浏 ...

  3. node.js模块本地代理模块(将自己本机/局域网)服务 代理到外网可以访问

    npm 模块 localtunnel模块可以. lt --port 7000  其中7000是本地服务端口 会分配一个动态的url. 局域网中查看本地ip用ifconfg 或者在系统偏好设置里面查看网 ...

  4. C#:MVC打印PDF文件

    在百度上找了许多PDF文件打印,但是符合我需求的打印方式还没看到,所以根据看了https://www.cnblogs.com/TiestoRay/p/3380717.html的范例后,研究了一下,做出 ...

  5. 部署NTP服务器进行时间同步

    NTP服务端:linl_S    IP:10.0.0.15 NTP客户端:lin_C    IP:10.0.0.16 NTP服务概述 1.原理 NTP(Network TimeProtocol,网络时 ...

  6. 从RGB扫描图到数字化等高线矢量图

    1 用arcgis 对地形图进行校正,主要是通过判断地图的坐标系统,然后将图层的坐标系统设置正确.选择图上的经纬网交点,对原图进行校正,一般要求四角和均匀布点. 2 二值化图像.如果是RGB图像,即彩 ...

  7. java 虹软ArcFace 2.0,java SDK使用、人脸识别-抽取人脸特征并做比对

    java人脸识别 虹软ArcFace 2.0,java SDK使用.人脸识别-抽取人脸特征并做比对 虹软产品地址:http://ai.arcsoft.com.cn/product/arcface.ht ...

  8. 修改Anaconda中的Jupyter Notebook默认工作路径

    这二天,安装了anaconda想更改jupyter的工作路径,在网上找了一下 方式1. 打开Windows的cmd,在cmd中输入jupyter notebook --generate-config如 ...

  9. mt19937 -- 高质量随机数

    优点:产生速度快, 周期大 用法: #include<bits/stdc++.h> using namespace std; int main() { mt19937 mt_rand(ti ...

  10. lua --- unpack

    unpack 返回数组中的所有元素,包括 nil,注意是数组,对于 k-v 是不返回的!!! do , ,o = } print(unpack(tab)) --默认从索引 1 开始 )) --从索引 ...