views:

53

answers:

1

I have a stand-alone JMS app that subscribes to several different JMS topics. Each topic has its own session and onMessage() listener. Each onMessage() method updates a common current value table - all the onMessage() methods update the same current value table.

I've read that the onMessage method is actually called on the JMS provider's thread. So, my question is: if all these onMessage() methods are called on a separate thread than my app, doesn't this present a concurrency problem since all these threads update a common CVT? Seems like I need to synchronize access to the CVT somehow?

A: 

Short answer to your question: YES, you need to take care of concurrency concerns when your JMS code is updating some common in-memory object.

However, I'm not sure what you mean by "common current value table"? If this is some database table, then database should take care of concurrency issues for you.

EDIT: it turned out that "common current value table" is a common in-memory object. As I mentioned earlier, in this case you need to handle the concurrency concerns yourself (Java concurrency tutorial).

There are mainly two approaches to this problem:

  • synchronization - suitable if you have low-contention or you are stuck with some non-threadsafe object, then your best choice is synchronization.
  • high-level concurrency objects that come with the JDK - best fit if you have high-contention and you are using some class from regular collections; just swap in an instance of concurrent collections.

In any case, it is highly recommended to do your own testing to choose the best approach for you.

If you would be dealing with expensive to create non-threadsafe stateless procedural code (no storage of data involved) then you could also use object pooling (e.g. Commons Pool), but this is not relevant in your current issue.

JMS onMessage() method is always called by the JMS provider's thread (also known as asynchronous calling).

Neeme Praks
Hi Neeme. The current value table would be an in-memory object like a static hashmap. I consider "my app" thread to be the main thread plus any thread my app creates. Just curious, how would you ensure mutual exclusion. Would you do something like an invokeLater() in each of the onMessage() threads? Like in GUI design?
Maxx
Edited my answer in response to your comment. Concerning threads, you are not supposed to spawn your own threads in JavaEE environment (see also this question: http://stackoverflow.com/questions/533783/why-spawning-threads-in-j2ee-container-is-discouraged). Furthermore, "main" thread is owned by the JavaEE container and not part of your application; invokeLater() is not useful in JavaEE, see my answer for description of approaches to mutual exclusion.
Neeme Praks
OK. THanks for the info. I would just add that I don't believe I'm running in a container per se. So far, I'm just running in the debugger of Eclipse. It has a main() method. In any case, I'm not spawning any threads.
Maxx
Even if you are currently not running in a container that does not mean that you eventually will not run in one. As you explicitly stated in your original question that you are using JMS that means that you will run in a container and that will have implications. Currently you may be running your code through unit-tests or similar means and in this case there will be only single thread and you will never come across concurrency-related bugs in your code. For example, you could use ActiveMQ for more realistic unit/integration testing: http://activemq.apache.org/how-to-unit-test-jms-code.html
Neeme Praks
BTW, if I managed to answer your question, then it would be nice if you would: vote up my answer and/or accept my answer. See also: http://stackoverflow.com/faq#howtoask
Neeme Praks
Neeme, sorry I'm such a novice using this web site. I *DO* appreciate your reponse! Your statement that using JMS means I will eventually run my app in a container is troubling to me. I had originally intended to run JMS from a J2SE type stand-alone app. I understand this is possible by reading various web sites. I have no objection to running as a client app in a container; I just thought it best to run as a J2SE. My reasoning has to do with the nature of my effort. I have to receive messages from OpenMQ, change the messages and republish to ActiveMQ. I didn't think a container would do this.
Maxx
Ok, sorry, I was confused about your use-case. In your case, it is perfectly reasonable to just start up two separate JMS clients in JavaSE and just forward messages. You could also run this inside a container, but that is another topic already.
Neeme Praks