[jboss-jira] [JBoss JIRA] (WFLY-3338) @Inject'ed JMSContext is not thread-safe

Brian Stansberry (JIRA) issues at jboss.org
Thu Jul 10 16:53:26 EDT 2014


     [ https://issues.jboss.org/browse/WFLY-3338?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Brian Stansberry updated WFLY-3338:
-----------------------------------

       Assignee: Jeff Mesnil  (was: Jason Greene)
    Component/s: JMS


> @Inject'ed JMSContext is not thread-safe
> ----------------------------------------
>
>                 Key: WFLY-3338
>                 URL: https://issues.jboss.org/browse/WFLY-3338
>             Project: WildFly
>          Issue Type: Bug
>      Security Level: Public(Everyone can see) 
>          Components: JMS
>    Affects Versions: 8.0.0.Final
>            Reporter: Rich DiCroce
>            Assignee: Jeff Mesnil
>
> Section 12.4.4 of the JMS 2.0 spec says:
> {quote}
> If a method is called on an injected JMSContext when there is a JTA 
> transaction (either bean-managed or container-managed), the scope of 
> the JMSContext will be @TransactionScoped.
> {quote}
> This is not currently true in WildFly. As a test case, suppose you have the following two beans:
> {code}
> import javax.annotation.Resource;
> import javax.enterprise.context.ApplicationScoped;
> import javax.enterprise.inject.Instance;
> import javax.inject.Inject;
> import javax.jms.JMSContext;
> import javax.jms.Topic;
> import javax.transaction.Transactional;
> @ApplicationScoped
> @Transactional
> public class AppScopedBean {
> 	
> 	@Inject
> 	private JMSContext jmsCtx;
> 	//private Instance<JMSContext> jmsCtx;
> 	@Resource(lookup = "jms/topic/test")
> 	private Topic topic;
> 	
> 	public void sendMessage() {
> 		jmsCtx.createProducer().setDisableMessageID(true).setDisableMessageTimestamp(true).send(topic, "a message");
> 		//jmsCtx.get().createProducer().setDisableMessageID(true).setDisableMessageTimestamp(true).send(topic, "a message");
> 	}
> }
> {code}
> {code}
> import javax.annotation.Resource;
> import javax.enterprise.concurrent.ManagedThreadFactory;
> import javax.enterprise.context.ApplicationScoped;
> import javax.enterprise.context.Dependent;
> import javax.enterprise.context.Initialized;
> import javax.enterprise.event.Observes;
> import javax.inject.Inject;
> @Dependent
> public class ThreadLauncher {
> 	@Resource
> 	private ManagedThreadFactory threadFactory;
> 	@Inject
> 	private AppScopedBean bean;
> 	
> 	void start(@Observes @Initialized(ApplicationScoped.class) Object event) {
> 		System.out.println("starting threads");
> 		for (int i = 0; i < 5; i++) {
> 			threadFactory.newThread(new SendRunnable()).start();
> 		}
> 		System.out.println("start finished");
> 	}
> 	
> 	private class SendRunnable implements Runnable {
> 		public void run() {
> 			System.out.println("starting to send");
> 			for (int i = 0; i < 100; i++) {
> 				bean.sendMessage();
> 			}
> 			System.out.println("done sending");
> 		}
> 		
> 	}
> 	
> }
> {code}
> If you deploy and run the above code, you will see a lot of this:
> {quote}
> 2014-05-12 16:46:02,936 WARN  [org.hornetq.core.client] (EE-ManagedThreadFactory-default-Thread-4) HQ212051: Invalid concurrent session usage. Sessions are not supposed to be used by more than one thread concurrently.: java.lang.Exception: trace
> {quote}
> That should not be happening if the JMSContext is really @TransactionScoped. The problem appears to be in org.jboss.as.messaging.deployment.JMSContextProducer, specifically the JMSContextWrapper.getDelegate() method. If two threads call it at the same time, the first will create a delegate but the second will receive the same delegate as the first, because the delegate doesn't get nulled until the transaction in the first thread completes.
> This means that both threads are using the same session at the same time, which is not allowed. I don't know how HornetQ detects concurrent use, but depending on how that works, it's also possible that messages will end up being part of the wrong transaction.
> A workaround is to inject Instance<JMSContext> instead of JMSContext directly (the two commented out lines of code). Since the JMSContext producer is @Dependent, each Instance.get() call will return a new instance, and only one thread will ever use any given instance.



--
This message was sent by Atlassian JIRA
(v6.2.6#6264)


More information about the jboss-jira mailing list