Can I start /spawn new java thread from within a MDB?
I have a requirement to do some parallel processing from code in MDB and then return the control back to MDB.
Requirement:
Message come to MDB , then some processing of code. Then two new slave thread are started which do some parallel work. Till then MDB is waiting. when threads finish the work. Then control is returned back to MDB, which completes the the related final/cleanup work.
Is it good idea to start a new thread ( Runnable) from MDB? If not then what should be the alternative?
It is a bad idea, if you are performing transactional work in the threads.
A thread that is currently performing work in a transaction started by the EJB container, is associated with a transaction context. In your case, the onMessage method in the MDB initiates a new transaction (unless you have specified a NotSupported descriptor), and the thread performing this transaction would be associated with a transaction context. Starting a new thread, does not propagate the transaction context to the child thread. This would result in a new transaction being created when the container detects that the child thread is attempting to access a transactional resource without a transaction context.
Although some (or most?) transaction managers support the presence of multiple threads possessing the same transaction context, this might (and most likely will) not apply to application initiated threads.
Starting new threads with in MDB is bad practice. It will work but the new threads are not in control of application container so can behave unpredictably. They can even mess-up the thread management which container is trying to maintain. Worst affect is if the application is deployed in cluster then user defined threads will fail miserably.
In your scenario : Instead of starting new threads , create new MDB with logic of thread ( This way it will be managed by contaner now) then send message to these new MDB. If you want the control back to parent MDB then, I think , use your parent MDB in global transactional so that parent MDB will wait for child MDB to finish and control will return back.
Starting a thread from an MDB violates the specification.
Enterprise JavaBeansTM,Version 3.0, EJB Core Contracts and Requirements states in section 21.1.2 Programming Restrictions:
An enterprise bean must not use thread synchronization primitives to synchronize execution of multiple instances.
The enterprise bean must not attempt to manage threads. The enterprise bean must not attempt
to start, stop, suspend, or resume a thread, or to change a thread’s priority or name. The enterprise bean must not attempt to manage thread groups.
You are fundamentally missing the point of Java EE and MDBs.
A Java EE container is a managed runtime environment. The principle idea behind the Java EE container is that by delegating certain orthogonal concerns, such as transaction management, to the container, the component remains focused on business logic and (in utopia) be a reusable component that makes little assumption about its runtime environment.
Prior to MDBs, the Java EE container was a passive-reactive system that allowed no means for coordinating the action of a container side asynchronous active agents. Message Driven Beans then addressed this, providing a standard way for you to kick off an asynchronous action, server side.
You have an original event e0 which is consumed by MBD0. On message, MDB0 will generate e1 and queue a message in response to MBD1, which will then do its work and send msg to MDB2, etc.
There you have a simple workflow of n sequential steps using pub/sub messaging semantics (and o/c with asynchronous semantics), and all threads involved are managed by the container. If you wish to have concurrent actors working and then collecting results and kicking off a final action, consider using patterns involving JMS topics.
Related
I work on the backend of a java web application. I added some multithreading to speed up a big data retrieval, and I used a few ExecutorServices I created in the process. However, I've read that it might not be a good idea to be creating threads this way in a web app, and that the 'com.ibm.websphere.asynchbeans.WorkManager' is maybe an option instead. It seems not very friendly to use in the backend though. According to the documentation, the work manager is a 'thread pool created for Java Platform, Enterprise Edition (Java EE) applications that use asynchronous beans'. I, as a very front end ignorant back end guy, don't even entirely know what a bean is. It doesn't really seem like the work manager is what I want, but if it's actually a bad idea to manually create an ExecutorService, I'm not sure what the best approach is.
Creating your own threads in the back end of a webapp is a bad idea for the following reason: Application Server container manages threads for you. So if you create your own threads in your app the container won't know about them and won't be able to manage them. Thus if you mismanage threads your app can cause memory leaks and other thread related problems. In theory the best way is to register some thread pool in your App Server and requests threads from the container using JNDI. But it might be an overkill. So sometimes, you may want to manage your own threads. So, in this case ExecutorService is the best way to go as it provides very nice API to manage your threads. Just make sure that as your application shuts down you shutdown your ExecutorService so no orphan threads are left behind. If you are careful about it then you can create your own threads. Just use them sparingly and be careful that you you shut down your ExecutorService when done or when Application shuts down. BTW there is a similar issue with ThreadLocal variables. You absolutely MUST invoke metod remove() in them when done, otherwise they will remain in the memory even if your app is shutdown, and only Application Server restart will clear them. This is a dangerous memory leak.
Just to expand on Michael Gantman's answer, which is a pretty good explanation, the JavaEE approach to allowing the container manage your threadpool is super easy to actually implement:
#Stateless
public class Foo {
#Asynchronous
#Override
public void doSomething() {
//all calls to this function are asynchronous
}
}
The #Aysnchronous takes care of the magic here, specifying to the container that this function should be called asynchronously and it's the container's responsibility to figure out what that means. Then calling out to your container managed threadpool to execute your function is as simple as:
#Stateless
public class Bar {
#EJB
Foo myFooEJB;
public void businessMethod() {
myFooEJB.doSomething();
}
}
Checkout these for more reading: javax.ejb.Asynchronous, Asynchronous method invocation. Getting maybe a little too into specifics because I know you're using IBM products, in JBoss, your Asynchronous comes as part of a subsystem configuration by specifying <async thread-pool-name="poolName"/> (https://docs.jboss.org/author/display/WFLY8/EE+Subsystem+Configuration)
where poolName should reference a pool such as:
<thread-pools>
<thread-pool name="poolName">
<max-threads count="10"/>
<keepalive-time time="100" unit="milliseconds"/>
</thread-pool>
</thread-pools>
But there is a better way if you're trying to submit, just some task to an ExecutorService which can be managed by the container:
#Resource
ManagedExecutorService executorService;
#Resource
ManagedScheduledExecutorService scheduledExecutorService;
java.io.PrintWriter out = ...;
void scheduleSomeStuff(){
scheduledExecutorService.schedule(new Runnable() {
#Override
public void run() {
out.println("Print out after roughly 15 seconds.")
}
}, 15, TimeUnit.SECONDS);
executorService.submit(new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
out.println("Print only once, when the task is run by the executor service's discretion.");
}
};
}
These two resources, specifically that I've reference here, run on different thread pools. At that, I originally posted something here using the #Asynchronous thread pool as an executor, but it's unnecessary since the container should already have one for you; hence the updated answer you see here now.
This, again, might be a little specific to JBoss, but in JBoss this is configured as a subsystem managed-scheduled-executor-services and managed-executor-services. These two subsystems have their own distinct thread pools that they utilize.
EDIT April, 2020
So I somehow found this answer again, and reread and am very confused at myself for not calling out the EJB specification explicitly. Not only is it a bad idea to do, you would be in direct violation of the EJB spec if you created your own threads.
JSR 345: Enterprise JavaBeans, Version 3.2 EJB Core Contracts and Requirements
Section 16.2.2 Bean Provider’s Responsibilities, Programming Restrictions:
The enterprise bean must not attempt to manage threads. The enterprise bean must not attempt to start, stop, suspend, or resume a thread, or to change a thread’s priority or name. The enterprise bean must not attempt to manage thread groups.
These functions are reserved for the EJB container. Allowing the enterprise bean to manage threads would decrease the container’s ability to properly manage the runtime environment.
In other words, NEVER attempt to manage your own threads in a web application. This quote is for the EJB spec but even within a ResourceAdapter, for example, the container provides a WorkManager via the BootstrapContext (see ResourceAdapter#start(BootstrapContext), BootstrapContext#getWorkManager()). There's never a reason to attempt to create/manage your own thread in a web application; never do it for any reason.
I'm trying to understand how to deal with threads within a Java client that connects to HornetQ. I'm not getting a specific error but fail to understand how I'm expected to deal with threads in the first place (with respect to the HornetQ client and specifically MessageHandler.onMessage() -- threads in general are no problem to me).
In case this is relevant: I'm using 'org.hornetq:hornetq-server:2.4.7.Final' to run the server embedded into my application. I don't intend this to make a difference. In my situation, that's just more convenient from an ops perspective than running a standalone server process.
What I did so far:
create an embedded server: new EmbeddedHornetQ(),
.setConfiguration()
create a server locator: HornetQClient.createServerLocator(false, new TransportConfiguration(InVMConnectorFactory.class.getName()))
create a session factory: serverLocator.createSessionFactory()
Now it seems obvious to me that I can create a session using hornetqClientSessionFactory.createSession(), create a producer and consumer for that session, and deal with messages within a single thread using .send() and .receive().
But I also discovered consumer.setMessageHandler(), and this tells me that I didn't understand threading in the client at all. I tried to use it, but then the consumer calls messageHandler.onMessage() in two threads that are distinct from the one that created the session. This seems to match my impression from looking at the code -- the HornetQ client uses a thread pool to dispatch messages.
This leaves me confused. The javadocs say that the session is a "single-thread object", and the code agrees -- no obvious synchronization going on there. But with onMessage() being called in multiple threads, message.acknowledge() is also called in multiple threads, and that one just delegates to the session.
How is this supposed to work? How would a scenario look in which MessageHandler does NOT access the session from multiple threads?
Going further, how would I send follow-up messages from within onMessage()? I'm using HornetQ for a persistent "to-do" work queue, so sending follow-up messages is a typical use case for me. But again, within onMessage(), I'm in the wrong thread for accessing the session.
Note that I would be okay with staying away from MessageHandler and just using send() / receive() in a way that allows me to control threading. But I'm convinced that I don't understand the whole situation at all, and that combined with multi-threading is just asking for trouble.
I can answer part of your question, although I hope you've already fixed the issue by now.
Form the HornetQ documentation on ClientConsumer (Emphasis mine):
A ClientConsumer receives messages from HornetQ queues.
Messages can be consumed synchronously by using the receive() methods which will block until a message is received (or a timeout expires) or asynchronously by setting a MessageHandler.
These 2 types of consumption are exclusive: a ClientConsumer with a MessageHandler set will throw HornetQException if its receive() methods are called.
So you have two choices on handling message reception:
Synchronize the reception yourself
Do not provide a MessageListener to HornetQ
In your own cunsumer Thread, invoke .receive() or .receive(long itmeout) at your leisure
Retrieve the (optional) ClientMessage object returned by the call
Pro: Using the Session you hopefully carry in the Consumer you can forward the message as you see fit
Con: All this message handling will be sequential
Delegate Thread synchronization to HornetQ
Do not invoke .receive() on a Consumer
Provide a MessageListener implementation of onMessage(ClientMessage)
Pro: All the message handling will be concurrent and fast, hassle-free
Con: I do not think it possible to retrieve the Session from this object, as it is not exposed by the interface.
Untested workaround: In my application (which is in-vm like yours), I exposed the underlying, thread-safe QueueConnection as a static variable available application-wide. From your MessageListener, you may invoke QueueSession jmsSession = jmsConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); on it to obtain a new Session and send your messages from it... This is probably alright as far as I can see because the Session object is not really re-created. I also did this because Sessions had a tendency to become stale.
I don't think you should want so much to be in control of your Message execution threads, especially transient Threads that merely forward messages. HornetQ has built-in Thread pools as you guessed, and reuses these objects efficiently.
Also as you know you don't need to be in a single Thread to access an object (like a Queue) so it doesn't matter if the Queue is accessed through multiple Threads, or even through multiple Sessions. You need only make sure a Session is only accesed by one Thread, and this is by design with MessageListener.
I understood the basic concept of Thread in standalone application. But, got confused in below areas.
1). In Java webapplication (servlet and Spring based)?
I hope, each request is handled by a different thread. Is this correct? Is there any other definition available?
2). what is a thread in Hibernate with Spring MVC?
Session factory is thread safe.. where as session object is not. What is mean by thread here?
Please help me to understand this.
1) The application server has a thread pool, when a request comes in it gets assigned a thread from the pool.The same thread calls the dispatcher servlet, which calls a controller, which calls a service, etc., and finally creates an HttpResponse and sends it to the client.
2) A usual pattern with Hibernate (if you're not using Seam conversations) is session-per-request:
2.4.2. Session-per-request pattern
This is the most common transaction pattern. The term request here
relates to the concept of a system that reacts to a series of requests
from a client/user. Web applications are a prime example of this type
of system, though certainly not the only one. At the beginning of
handling such a request, the application opens a Hibernate Session,
starts a transaction, performs all data related work, ends the
transaction and closes the Session. The crux of the pattern is the
one-to-one relationship between the transaction and the Session.
The transaction is stored by Spring in a threadlocal variable. So the thread has a Hibernate session (which is confined to that thread), and it is associated with a transaction (or a stack of transactions, since they can be nested).
I'm attempting to utilize the .NET Kaazing client in order to interact with a JMS back-end via web sockets. I'm struggling to understand the correct usage of sessions. Initially, I had a single session shared across all threads, but I noticed that this was not supported:
A Session object is a single-threaded context for producing and consuming messages. Although it may allocate provider resources outside the Java virtual machine (JVM), it is considered a lightweight JMS object.
The reason I had a single session was just because I thought that would yield better performance. Since the documentation claimed sessions were lightweight, I had no hesitation switching my code over to use a session per "operation". By "operation" I mean either sending a single message, or subscribing to a queue/topic. In the former case, the session is short-lived and closed immediately after the message is sent. In the latter case, the session needs to live as long as the subscription is active.
When I tried creating multiple sessions I got an error:
System.NotSupportedException: Only one non-transacted session can be active at a time
Googling this error was fruitless, so I tried switching over to transacted sessions. But when attempting to create a consumer I get a different error:
System.NotSupportedException: This operation is not supported in transacted sessions
So it seems I'm stuck between a rock and a hard place. The only possible options I see are to share my session across threads or to have a single, non-transacted session used to create consumers, and multiple transacted sessions for everything else. Both these approaches seem a little against the grain to me.
Can anyone shed some light on the correct way for me to handle sessions in my client?
There are several ways to add concurrency to your application. You could use multiple Connections, but that is probably not desirable due to an increase in network overhead. Better would be to implement a simple mechanism for handling the concurrency in the Message Listener by dispatching Tasks or by delivering messages via ConcurrentQueues. Here are some choices for implementation strategy:
The Task based approach would use a TaskScheduler. In the MessageListener, a task would be scheduled to handle the work and return immediately. You might schedule a new Task per message, for instance. At this point, the MessageListener would return and the next message would be immediately available. This approach would be fine for low throughput applications - e.g. a few messages per second - but where you need concurrency perhaps because some messages may take a long time to process.
Another approach would be to use a data structure of messages for work pending (ConcurrentQueue). When the MessageListener is invoked, each Message would be added to the ConcurrentQueue and return immediately. Then a separate set of threads/tasks can pull the messages from that ConcurrectQueue using an appropriate strategy for your application. This would work for a higher performance application.
A variation of this approach would be to have a ConcurrentQueue for each Thread processing inbound messages. Here the MessageListener would not manage its own ConcurrentQueue, but instead it would deliver the messages to the ConcurrentQueue associated with each thread. For instance, if you have inbound messages representing stock feeds and also news feeds, one thread (or set of threads) could process the stock feed messages, and another could process inbound news items separately.
Note that if you are using JMS Queues, each message will be acknowledged implicitly when your MessageListener returns. This may or may not be the behavior you want for your application.
For higher performance applications, you should consider approaches 2 and 3.
From the javadoc for Session it states:
A Session object is a single-threaded context for producing and consuming messages.
So I understand that you shouldn't use a Session object from two different threads at the same time. What I'm unclear on is if you could use the Session object (or children such as a Queue) from a different thread than the one it created.
In the case I'm working on, I'm considering putting my Session objects into a pool of available sessions that any thread could borrow from, use, and return to the pool when it is finished with it.
Is this kosher?
(Using ActiveMQ BTW, if that impacts the answer at all.)
I think the footnote from section 4.4 in the JMS 1.1 spec sheds some light:
There are no restrictions on the number of threads that can use a Session object or those it creates. The restriction is that the resources of a Session should not be used concurrently by multiple threads. It is up to the user to insure that this concurrency restriction is met. The simplest way to do this is to use one thread. In the case of asynchronous delivery, use one thread for setup in stopped mode and then start asynchronous delivery. In more complex cases the user must provide explicit synchronization.
By my reading of the spec what you want to do is OK, provided you correctly manage concurrency.
Sadly the JMS docs are often not written as clearly or precisely as we might like :o(
But reading the spec I'm now pretty convinced you really shouldn't access the session from other threads, even if you guarantee there's no concurrent access. The bit of the javadoc that swung it for me was:
Once a connection has been started,
any session with a registered message
listener(s) is dedicated to the thread
of control that delivers messages to
it. It is erroneous for client code to
use this session or any of its
constituent objects from another
thread of control. The only exception
to this is the use of the session or
connection close method.
Note the clear use of 'thread of control' and the singling out of 'close()' as the only exception.
They seem to be saying that even if you're using asynchronous message consumption (i.e. setMessageListener) - which means you get called back on another thread created by JMS to receive messages - you're never allowed to touch the session or related objects again from any other thread, because the session is now 'dedicated' to the JMS delivery thread. For example, I assume this means you couldn't even call message.acknowledge() from another thread.
Having said that, I only just noticed that we haven't been obeying this constraint, and have yet to notice any ill effects (using SonicMQ). But of course if you don't obey the standard, all bets are off, so I guess we need to obey the 1-thread 1-session rule to stay safe.