JMS Session和线程简析

JMS Session和线程简析

JMS API打交道主要是Session对象. HibernateSession设计思路一样, JMS Session是为单线程运行在单线程之下. 有了这点认识, 在并发控制线程同步方面就游刃有余得多了. 查阅官方文档, 总结如下, 下文主要翻译自JavaTM Message Service Specification V1.1

 

l         Session的创建

1. Session是单线程的上下文, Thread Safe.

2. 通过JMS Connection来创建, 相对于Connection来说, 被视为轻量级对象, 换言之, 运行时创建亦无碍.

3. 典型的JMS Client会创建一个Connection, 一个或者若干个Sessions, 若干个消息Producer,Consumer. Hibernate, Session是封装了一个Connection的对象. 而在JMS, 一个Connection往往包含若干个Session.

 

l         Session的关闭

1. Sessions invoke close之时, 若有Message Listener正在running, close并不会立即返回, 而是阻塞等待完成.

2. Sessions invoke close之时, 若有receivepending, close可能导致receive返回null.

3. Sessions关闭后无需对其相关资源进行手动关闭.

4. Sessions invoke close之时, 将导致Transaction rollback.

5. 一旦Sessionsclose, 使用Messageacknowledge, 将导致异常. 但信息本身还是可用的.

6. 关闭已经closeSession不会导致异常.

 

l         Session的一般使用方式

1. 一种方式: 具有一个同步Consumer的线程, 会阻塞直到有消息到达. 收到消息后, 该线程会使用与Consumer同一个session下的一个或者多个Producer去发消息. 换言之, 这种方式可以用来模拟了这样一套流程: 等待request ==>> 接收到request ==>> 返回response.

2. 另一种方式: 由一个线程setup一个Session, 以及其若干消息Producer, 若干异步Consumer. 由于单线程, Message Listener执行中, Producer会被exclusive. 另外一点是, Session注册了多个Message Listener, 这些Message Listener会被顺序执行, 安全地共享Session的资源.

3. 如果要求一个线程produce消息, 同时另外一个线程consume消息, client code里面应该使用分开的两个Session. 多数情况下, 通过Sessionspartition, client会更natualsimple, 伸缩性更强, 更有效应对日益增长的complexityconcurrency. 我想, 这也是最佳实践了.

4. Connection处于stop状态, 此时Session正在setup, 在完全准备好前, 客户端无需接收消息, 这是preferred策略, 它消除了setupprocess之间不可预期的冲突.  Connection在接收消息的时候, 创建和配置Session是可以的, 但是, 要注意保证消息Producer,Consumer,Listener创建的顺序. 例如, Message Listener中使用的消息Producer还处于创建之中. 或者由于Message Listener注册顺序错误引起接收消息顺序错误.

 

l         Session Error Pattern

1. 同一个Session之下, 一个线程尝试同步接收, 另外一个线程也在尝试同步接收, 这种用法是错误的. Session是单线程的.

2. 一旦Connection start之后, 注册有一个或者若干个Message ListenerSession, 就会交给传送消息给它的线程来控制. 因而, client code里面用另外的线程来控制将Session及其产生的对象是错误的. 唯一的例外, 是对Session进行关闭.

3. 由于Session单线程(single-thread-of-control)的限制, 注册有Message ListenerSession, 无论控制是交给了传送消息给它的线程, 还是交给了client code中对其进行初始化的线程, 试图使用synchronouly receive是错误的. 亦即, 在同一Session, 同步接收和异步接收不允许Combine.

4. 为一个Session配置多个Message Listener, Connection必须(must be)处于stop状态. 已经注册了一个Message Listener, Session处于传送消息线程的控制之下, 这时候, 客户端线程是不能再对其进行配置的.

 

l         Multiple Sessions

client一般会创建multiple Sessions, 每个Session都会有独立的Producer, Consumer. 对于Pub/Sub模型, 每条消息会交给每个订阅者, 消息传送给一个订阅者不会阻塞发送给其他另外的订阅者. 对于PTP模型, JMS没有具体界定, 对同一条Queue进行并发消息收取者的定义. JMS不禁止JMS提供者对并发消息接收的支持, 因而, 消息delivery到多个QueueReceivers取决于provider的实现. 应用程序depend on multiple QueueReceivers会导致不可移植性. 对于监听同一条Queue的多个Message Listener, 会执行哪一个由provider决定了.

 

l         client code序列(顺序)化执行

虽然Java语言提供内置的多线程支持, 但是编写多线程应用程序仍然是相当困难. 因此, JMSclient code不会多线程执行, 除非client显式要求. 一种方式是定义一个Session, 并顺序化(serializes)异步消息传送(asynchronous delivery of messages). 如果要异步接收消息, client通过一个MessageConsumer注册一个object实现MessageListener接口. 而实际上, 一个Session使用单线程去运行它所有的MessageListeners. 当线程在忙于执行一个Listener, 这个Session其他的Listener的异步消息传送必须等待.

 

l         并发消息传送(Concurrent Message Delivery)

client如果要求并发消息传送, 可以使用multiple sessions. 实际上, 每个SessionListener线程是并发运行. 当一个Session的一个Listener正在执行, 另外一个Session的一个Listener也可以在执行. 要注意的是, JMS不提供并发处理Topic消息集(topic's message set)的设施. client可以使用single Consumer来实现所有多线程逻缉, 然而, 这样做并不可靠. 因为JMS并不提供这种条件下要求的并发transaction处理设施. 不好翻译, 原文如下:

 

JavaTM Message Service Specification V1.1 写道
Note that JMS itself does not provide the facilities for concurrently processing a topic’s message set (the messages delivered to a single consumer). A client could use a single consumer and implement all the multithreading logic needed to concurrently process the messages; however, it is not possible to do this reliably, because JMS does not have the transaction facilities needed to handle the concurrent transactions this would require.

 

你可能感兴趣的:(thread,多线程,Hibernate,jms)