Legally Starting Threads/Synchronizing EJBs - Hell Or Heaven

EJB spec does not allow starting and managing threads ...in general. With @Singleton you can do whatever you want even:

With Bean Managed Concurrency demarcation, the container allows full concurrent access to the Singleton bean instance. It is the responsibility of the bean developer to guard its state as necessary against synchronization errors due to concurrent access. The bean developer is permitted to use the Java language level synchronization primitives such as synchronized and volatile for this purpose. [EJB 3.1 spec, page 111]

You only need to apply an additional annotation on a @Singleton and do whatever you want - at least synchronization-wise:

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class InefficientHelloWorld {
    //AtomicInteger would be a lot better.
    private static volatile int counter = 0; 
    //synchronized just for demo purposes, o.k with CMT.Bean.
    public synchronized void sayHello(){
        new Thread(new Runnable() {    //still not allowed - but it works
            public void run() {
			  //out.println is not a best practice either...
                System.out.println("Hello World: " + counter++);

            }
        }).start();
    }
}

In the majority of all cases it is better to use just @Stateless beans and just let the container manage threads and synchronization for you.
@Asynchronous is far better and easier to use , than the example above.
The "working" example was pushed into http://kenai.com/projects/javaee-patterns/. The name of the project is "BeanManagedConcurrency".

Starting and managing threads in the application code is hard to implement, monitor and debug - it is by no means a best practice.

[See Lightweight Asynchronous Facade pattern, page 65 in "Real World Java EE Patterns Rethinking Best Practices" book for more in-depth discussion] 

Comments:

I'm not sure that your reasoning is correct. The section of the EJB 3.1 spec that you've quoted only speaks about using synchronization primitives (synchronized blocks, volatile variables), but it does in no way mention that you're allowed to start new threads.

Considering the implications of starting new threads - you could create hundreds if your application is under load, and thus interfer with the application server's operation - I believe that the opposite is true, and would always refrain from starting my own threads.

Posted by Rolf Schäuble on March 15, 2010 at 02:49 PM CET #

Rolf,

you are actually right. Bean Managed Concurrency was intended just for synchronization (synchronized, volatile etc.) purposes.

I personally never used BMC in real world, @Stateless with @Asynchronous were just enough. Starting threads directly in code is still officially not allowed (actually gray-zone), inefficient and hard to control.
But: one could inject the JCA connector here and delegate the thread "creation" to it. This would be perfect. You can still start threads in servlets - it is also o.k.

The above sample works perfectly on Glassfish v3, but it is by no means a best-practice.

Will change the post a bit to make it clearer,

thanks for the hint,

adam

Starting threads in Java EE code is an absolute anti-pattern and rarely needed (never did that), if you really have to, you should use at least an Executor for it.

Posted by Adam Bien on March 15, 2010 at 03:17 PM CET #

@Rolf,

thought about your comment again :-). My reasoning is:
The worst possible thing, which may occur is not inefficiency, but inconsistency. Starting threads is not as bad, as accessing unsynchronized shared memory concurrently.

You will find a possible bottleneck in the next stress test. Finding inconsistencies is a lot harder to achieve...
Therefore I would still avoid singletons, static and so synchronization primitives in Java EE environment. And having @Asynchronous, JMS and JCA available minimizes the desire for threads in your application code.

My thoughts were: if volatile + synchronized, why not threads? I remember we discussed the topic a bit in the EG - I thought actually that the rule was loosened for BMC in the spec - but it is not the case yet.

thanks again for the constructive comment!,

adam

Posted by Adam Bien on March 15, 2010 at 03:40 PM CET #

There are several usecases for this as soon you have to solve problems with finer granularity as sessions (or even tasks in general) e.g. computation on ForkJoin pools. (even by using scala actors you already created a threadpool).

The spec should allow application threads - as long the appserver doesn't cheat I see no reason why using threads would be more dangerous as outside of a container.

Posted by michael bien on March 15, 2010 at 05:42 PM CET #

@Michael,

you can absolutely do that - in Servlets, CDI and in JCA. The EJB 3.1 spec does not allow it formally - but it works in most cases. Thread usage, however, may lead to portability issues.

Computation / batch processing can be perfectly solved with @Asynchronous.

If you really want to launch your own threads, you could also do that in CDI - you could even introduce your own scopes.

regards,

adam

Posted by Adam Bien on March 15, 2010 at 05:56 PM CET #

Interesting discussion.

But to me when you use a container, you surrender the right to runtime services like threading. The idea of EJB as a component model is that you're isolated to a sandbox and can focus on that one area. When the application developer creates threads (or does other runtime/IO calls), it becomes possible to affect other applications on the server. So this IMO is a no-no. :)

S,
ALR

Posted by Andrew Lee Rubinger on March 15, 2010 at 07:38 PM CET #

@ALR,

absolutely no-no. Never used threads so far in the EJBs. But why not allow them in @Singleton BMC.Bean?

thanks for your comment!,

adam

Posted by Adam Bien on March 15, 2010 at 07:51 PM CET #

Adam:

Because @Singleton lets you manage your concurrency policy, but not the Thread itself. Imagine the app developer starts a non-daemon Thread outside the context of the runtime environment; this could block the server from shutting down safely.

S,
ALR

Posted by Andrew Lee Rubinger on March 15, 2010 at 10:22 PM CET #

Note that there are mechanisms around this. In JBossAS for instance, the Application Server makes available a project called "JBoss Threads", from which the client may request a new thread from a given factory. Because the AS is controlling the lifecycle of these Threads, they're not managed by the application (just requested and used). So that's safe.

In short; if you can *get* a Thread from the runtime environment, that's OK. But EJB spec prohibits creation from the application for a reason. :)

S,
ALR

Posted by Andrew Lee Rubinger on March 15, 2010 at 10:25 PM CET #

@ALR,

interesting pointer. But in either way it wouldn't be portable. A very lean JCA would also do the job in portable way.

Except WebSphere few years ago, thread creation always worked on servers like: WLS, JBoss, GlassFish. The security manager wasn't configured too restrictively (I created threads for load / test / training purposes).

thanks for the pointer - will check that out.

adam

Posted by Adam Bien on March 15, 2010 at 10:47 PM CET #

all we need is a standardized 'ThreadPoolManager' returning the appserver's implementation of an ExecutorService ;)

Posted by Michael Bien on March 16, 2010 at 02:33 AM CET #

@Michael,

1. use @Asynchronous (very similar)
2. Use JCA -> even closer
3. Wrap Executor service and inject it as CCI - very close
4.Use CDI and inject it to EJBs - it is possible now.
5.JMX was always an option
6. Servlets works also - but is a bit strange

I would just officially allow (thats only a sentence) to use threads in ConcurrencyManagement(Bean). Then you could create your own threads/pools - which could be easily injected to whatever you want. As I said its just a theoretical discussion - in practice the current situation is sufficient for > 90% (in my case 99%) of all use cases...

thanks for your comment!,

adam

Posted by Adam Bien on March 16, 2010 at 11:04 AM CET #

according to the Oracle JEE techcast some concurrency JSRs might be resurrected for JEE7 ;)

Posted by Michael Bien on March 16, 2010 at 08:36 PM CET #

@Michael,

There were already several proposals in the past - looking forward to Java EE 7 :-),

adam

Posted by Adam Bien on March 17, 2010 at 11:21 AM CET #

I'm looking forward to adopting JDK's 7 fork/join framework. However, as it stands this would not be directly allowed in an EJB.

So, this means I would have to do my 'intensive' computations inside the servlet container. This would be doable of course (it's basically what I do know in Java EE 5), but it kinda defeats the purpose of the servlet container.

With some fiddling with JCA it might be possible to get a hold of the container managed threads, let the JDK 7 fork/join executor use these and then inject the executor in whatever EJB that needs to submit some (recursive) computation intensive task.

This would certainly be a nice challenge to try to implement on a rainy Sunday afternoon, but maybe something like this should be more easily provided by a standardized API in the (near) future.

@Asynchronous in Java EE 6 is a very good step in the right direction and will work for a lot of use cases. I sincerely hope Java EE 7 will continue this path and provide direct support for the superb join/fork framework from JDK 7.

Posted by Robert Tuinman on March 20, 2010 at 03:00 PM CET #

Some containers , like Websphere , Weblogic provides WorkManager API what works prefect for asynchronous processing.

Posted by miluch on November 12, 2010 at 04:21 PM CET #

What about a new Pattern for your Book's second edition???

Just something like:

@Connector(...)
public class ThreadExecutor implements ResourceAdapter {

BootstrapContext ctx;

public void start(BootstrapContext ctx) {
this.ctx = ctx;
}

// do the other stuff

public void runLater(Runnable r) {
ctx.getWorkManager().doWork(new DelegatingWork(r));
}
}

public class DelegatingWork implements Work {

Runnable delegate;

public DelegatingWork(Runnable r) {
this.delegate = r;
}

public void run() {
this.delegate.run();
}

public void release() {}
}

then:

@Stateless
public class NichtDieBohne {
@Resource
ThreadExecutor te;

@Asynchronous
public void doStuff() {
te.runLater(new Runnable() {
public void run() {
//... do the stuff ...
}
});
}
}

Just my two cents...
Regards,
Robert

Posted by Robert on November 13, 2010 at 12:48 AM CET #

@Robert,

1. thanks!
2. There will be some cool new patterns in the book (press.adam-bien.com)
3. There are no editions, just iterations :-)
4. A similar pattern will be described.
5. I'm working on second iteration and another book concurrently.

thanks for nice comment!,

adam

Posted by adam-bien.com on November 13, 2010 at 05:14 PM CET #

@Robert: question for you: you show the resource adapter *itself* being injected...I assume you'd have to also write a ManagedConnectionFactory implementation, a ManagedConnection, and a user connection and user connection factory class as well?

I've also asked this question in more detail here: http://stackoverflow.com/questions/4199146/does-a-jca-1-6-resourceadapter-need-a-managedconnectionfactory

Posted by Laird Nelson on November 17, 2010 at 01:13 AM CET #

@Laird Nelson:

Well... you could use the ManagedConnection & ManagedConnectionFactory, bind it to the ResourceAdapter (let the ManagedConnectionFactory-Implementation implement ResourceAdapterAssociation interface, then, by contract, the ResourceAdapter is "injected" into the mcf) and delegate to the ResourceAdapter's WorkManager. Well. It's not that tricky thing anymore with JCA 1.6...

OR:

Just in the start() method, do a "native" bind:

InitialContext ic = new InitialContext();
ic.rebind("ThreadExecutor", this);

But!!! Be careful in one case: If you like to use the ThreadExecutor in a @Singleton, the start() method might not be called before the instantiation of that singleton bean, so the JNDI-Name is not bound at this point.

Then, Adam's suggestion would work perfectly!

Posted by Robert on November 17, 2010 at 06:05 PM CET #

@Adam, @Laird Nelson:

well, the suggested solutions (either ConcurrencyManagementType.Bean or the WorkManager-Propagation) are just "tricks" to propagate the WorkManager / ThreadPool from the RA-Layer to the Business-Logic.

But: It should be considered, if this is really a task for the business-logic. Should the businesslogic be thread-aware???

Or: Are these thread-aware-things just logic that belongs better to a ResourceAdapter completely? (and you have to write a complete RA for that logic and just delegate from businesslogic to the RA)

Sometime it's hard to decide... :-)

r.

Posted by Robert on November 17, 2010 at 06:13 PM CET #

I need to execute some stuff asynchronously after a EJB method is called. This need seems to be fulfilled in EJB 3.1 but unfortunately we're not there yet and have to use 3.0 version.

What would you suggest as the simplest way and are there caveats?

Can you briefly describe how to use JMS to do this...

Posted by dimitri on October 13, 2011 at 07:33 PM CEST #

Hello Adam,

Is there any elegant way to use a Singleton for a long running task?
E.g. waiting for packets from an 3rd party library.

greetings
Markus

Posted by Markus on April 10, 2012 at 11:20 PM CEST #

Hello Adam,

I'm working on an interceptor implementation that splits a single bean invocation (with a large collection parameter) into a number of invocations (each with just a fraction of the original parameter). The fractional invocations can be queued and asynchronously processed in parallel very fast.
By applying an interceptor all the "magic" is hidden from the business logic. Unfortunately the interceptor is unable to clone the InvocationContext object. Thus it performs all subsequent invocations itself instead of leaving them to the container by calling InvocationContext.proceed(). And thus the container-managed chain concerning transaction, concurrency and security is cut.
Could this cut be avoided by implementing a resource adapter that provides for an ExecutorService which in turn could be invoked by the interceptor? Any other suggestions would be appreciated as well.

regards,
Thomas

Posted by Thomas on April 18, 2013 at 09:10 PM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
...the last 150 posts
...the last 10 comments
License