Adam Bien's Weblog

Monday Mar 15, 2010

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] 


[my tweets]  Rss My book: Real World Java EE - Rethinking Best Practices

Kommentare:

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.

Gesendet von Rolf Schäuble am March 15, 2010 at 01: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.

Gesendet von Adam Bien am March 15, 2010 at 02: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

Gesendet von Adam Bien am March 15, 2010 at 02: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.

Gesendet von michael bien am March 15, 2010 at 04: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

Gesendet von Adam Bien am March 15, 2010 at 04: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

Gesendet von Andrew Lee Rubinger am March 15, 2010 at 06: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

Gesendet von Adam Bien am March 15, 2010 at 06: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

Gesendet von Andrew Lee Rubinger am March 15, 2010 at 09: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

Gesendet von Andrew Lee Rubinger am March 15, 2010 at 09: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

Gesendet von Adam Bien am March 15, 2010 at 09:47 PM CET #

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

Gesendet von Michael Bien am March 16, 2010 at 01: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

Gesendet von Adam Bien am March 16, 2010 at 10:04 AM CET #

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

Gesendet von Michael Bien am March 16, 2010 at 07:36 PM CET #

@Michael,

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

adam

Gesendet von Adam Bien am March 17, 2010 at 10: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.

Gesendet von Robert Tuinman am March 20, 2010 at 02:00 PM CET #

Senden Sie einen Kommentar:
  • HTML Syntax: Ausgeschaltet
Meta-stuff / Interviews
My Recent Book
Java One 2009
CommunityOne East N.Y.C
JavaONE 2008 Interview
Search
...the last 150 posts
...the last 10 comments
greenfire.dev.java.net
Links
my.netbeans.org
Visitors
License