Hot questions for Using Enterprise JavaBeans in concurrency

Question:

I'm migrating my EJBs to Spring beans and i have an issue with concurrency on some beans i have annotation @Lock(LockType.READ) or @Lock(LockType.WRITE) on methods and class when concurrency was managed by container, but in Spring concurrency is managed by bean, what equivalent i could do in Spring regarding for locking two simultaneous read/write actions ?

For example on this class :

@Singleton
@Lock(READ)
public class SharedSingletonBean {
  private String data;
  private String status;

  public String getData() {
    return data;
  }

  public String getStatus() {
    return status;
  }

  @Lock(WRITE)
  public void setStatus(String newStatus) {
    status = newStatus;
  }
}

Answer:

For @Lock(READ), you have nothing to do as the READ value means that the method does only reading and that it can be concurrently accessed, or shared, with several clients.

It is the case for example for these two methods :

public String getData() {
    return data;
}

public String getStatus() {
    return status;
}

For @Lock(WRITE) as this one :

@Lock(WRITE)
public void setStatus(String newStatus) {
    status = newStatus;
}

it means that the method does writing. So actually, the WRITE value makes the container to prevent any client to invoke the method if another client executing it. To do the same thing with Spring, using the volatile modifier for the String field could be enough as you do only an assignment in the method. You would not have concurrency or no updated value issue as an assignment for a volatile variable is always atomic and updated for other threads and with this solution, as in your actual case, the last one client is always right. Also, as a side note, I am not very convinced of the correct use of @Lock READ and WRITE here.

If you have more statements and that this could not be invoked atomically and in a transparent way for other clients, you could use a synchronized statement on the current object :

 public void setStatus(String newStatus) {
    synchronize(this){
       myStatement();
       myOtherStatement();
       status = newStatus;
    }
  } 

Question:

Given a Singleton like this one:

@Singleton
public class waitingTimeManager {

    private Map<Integer, Object> waitingTimes;

    @PostConstruct
    public void setup() {
        waitingTimes = new HashMap<>();
    }

    @Lock(LockType.READ)
    public boolean shouldWeWait(Integer id) {
        if (waitingTimes.containsKey(id)) {
            boolean wait = someLogic(waitingTimes.get(id));
            if (!wait) {
               // we don't need to wait for it anymore
               stopWaiting(id);
            }
            return wait;
        }
        return false;
    }

    @Lock(LockType.WRITE)
    public void stopWaiting(Integer id){
        waitingTimes.remove(id);
    }

}

The initial method shouldWeWait can be accessed at the same time by several threads. The other stopWaiting will need to get a write lock.

Will the call to stopWaiting inside shouldWeWait try to get a WRITE Lock? or simply execute it as it already got the READ Lock initially?


Answer:

No, it won't try to get write lock.

Container job is done within interceptors, wrapping EJB method calls. For example, when stateless BeanA calls your singleton - it does so through proxy, which makes possible the guarantees given by container (retrieving lock, etc.).

But in this case, it's just a normal method call (stopWaiting), not wrapped by proxy, so no place for magic.

Question:

If I have a stateful class that requires a utility-like stateless class to perform an operation on it. These stateful classes are kept in a list in a container (stateful) class. This is what I would do with plain Java:

class Container {
    List<Stateful> sfList;
}

class Stateful {

    List<String> list;

    void someMethod() {
        list.add("SF");
        Stateless.foo(this);
}

class Stateless {
    public static void foo(Stateful sf) {
        sf.getList().add("SL");
    }
}

and inside main this is the procedure:

Stateful sf = new Stateful();
sfList.add(sf);
sf.someMethod();

Now with JavaEE CDI I would do:

class StatefulBean {

    List<String> list;

    @Inject
    StatelessBean slsb;

    void someMethod() {
        list.add("SF");
        slsb.add(this);
}

@Stateless
class StatelessBean {
    public void add(StatefulBean sfsb) {
        sfsb.add("SL");
    }
}

In this case all StatefulBean could access a shared pool of StatelessBean with no concurrency issues and it will scale properly with requests.

However, since Stateful is not a managed bean I can't inject into it and so I used the utility class instead. Also I'm creating Stateful with a constructor so I can't inject into it the stateless bean (I will get a NPE using it).

My questions are:

  • Are there concurrency and scalabilty differences between the stateless injection approach (provided it would work) and the utility class approach?
  • How can I make the EE injection approach work?

Answer:

Are there concurrency and scalabilty differences between the stateless injection approach (provided it would work) and the utility class approach?

Yes there are, primarily around the loss of management. The way you're instantiating Stateful on every invocation of the method, there's no pooling involved. This is going to lead to you creating more instances than you probably need.

Another loss is on the scalability side. Where the container will manage the passivation and activation of your stateful bean in a distributed environment, the manual approach will see to it that you manage your own activation and passivation.

Since Stateful is not a managed bean..

Incorrect. According to the CDI Spec, any java class that meets the listed criteria (in your case, a default no-arg constructor) is a managed bean. That means that you could @Inject StatelessBean into Stateless and the container would oblige. To allow this level of management, you'll need to set bean-discovery-mode=all in your beans.xml.

Even with the (apparently needless) circular reference, normal Java concurrency rules apply: as long as the state that you're manipulating is not static or in a static class, you're threadsafe. Each threaded call to that static method still operates on a separate stack, so no problems there.

How can I make the EE injection approach work? If you need on-demand instantiation of Stateless(or any other bean really), use the CDI Instance to programmatically obtain a managed instance of any class you want. You can now add something like this to Container:

@Inject @Dependent Instance<Stateful> stateful;

    @PostConstruct
     public void createStateless(){
         //instantiate sfList;
         sfList.add(stateful.get()); //execute as many times as you need
     }

Question:

The Setup:

I'm trying to show the progress of a scheduled task in my servlet response. I have a simple test setup that uses three classes to "increment state" of a task for 20 seconds (at 4 second intervals on the minute):

Scheduler:

import javax.annotation.PostConstruct;
import javax.ejb.Schedule;
import javax.ejb.Singleton;

@Singleton
public class TaskScheduler {

    private Task task;

    @PostConstruct
    public void init() {
        task = new Task();
    }

    @Schedule(hour="*", minute="*", second="0")
    public void run() {
        (task = new Task()).run(); // no new Thread, this runs in-line
    }

    public String getState() {
        return task.getState();
    }
}

Task:

import java.util.Date;

public class Task implements Runnable {

    private volatile String state = String.format("%s: %s\n",
            Thread.currentThread().getName(),
            new Date());

    public String getState() {
        return state;
    }

    @Override
    public void run() {
        long end = System.currentTimeMillis() + 20000;
        while (System.currentTimeMillis() < end) {
            String s = Thread.currentThread().getName();
            try {
                Thread.sleep(4000);
            } catch (InterruptedException ex) {
                s = ex.getMessage();
            }
            state += String.format("%s: %s\n",
                    s,
                    new Date());
        }
    }
}

Servlet:

import java.io.IOException;
import java.util.Date;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/simple")
public class SimpleServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @EJB
    private TaskScheduler scheduler;
    private String prefix = String.format("%s constructed at %s\n",
            Thread.currentThread().getName(),
            new Date());

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        prefix += String.format("%s served at %s\n",
                Thread.currentThread().getName(),
                new Date());
        String s = String.format("%s%s",
                prefix,
                scheduler.getState());
        resp.getOutputStream().write(s.getBytes());
    }
}


The Problem:

While the task is idle, doGet returns immediately with appropriate timestamps/etc but while the task is in progress it is delayed, as if blocking on access to the task's state.

Here's some actual sample output I copied from my browser during a delay:

http-listener-1(3) constructed at 2014-09-11 17:01:36.600 http-listener-1(3) inited at 2014-09-11 17:01:36.601 http-listener-1(3) served at 2014-09-11 17:01:36.601 http-listener-1(1) served at 2014-09-11 17:01:56.174 http-listener-1(2) served at 2014-09-11 17:01:57.541 http-listener-1(4) served at 2014-09-11 17:01:58.558 http-listener-1(3) served at 2014-09-11 17:01:59.444 http-listener-1(3): 2014-09-11 17:01:36.603

and here's the output that came (all at once) after the delay:

http-listener-1(3) constructed at 2014-09-11 17:01:36.600 http-listener-1(3) inited at 2014-09-11 17:01:36.601 http-listener-1(3) served at 2014-09-11 17:01:36.601 http-listener-1(1) served at 2014-09-11 17:01:56.174 http-listener-1(2) served at 2014-09-11 17:01:57.541 http-listener-1(4) served at 2014-09-11 17:01:58.558 http-listener-1(3) served at 2014-09-11 17:01:59.444 http-listener-1(5) served at 2014-09-11 17:02:00.502 __ejb-thread-pool2: 2014-09-11 17:02:00.004 __ejb-thread-pool2: 2014-09-11 17:02:04.005 __ejb-thread-pool2: 2014-09-11 17:02:08.006 __ejb-thread-pool2: 2014-09-11 17:02:12.006 __ejb-thread-pool2: 2014-09-11 17:02:16.006

Things I've tried:

  • removing the "volatile" keyword on Task's "state"
  • adding `@Lock(LockType.READ)` to the Scheduler's getState method
  • adding `@Asynchronous` to the Scheduler's run method

I'm deploying to a local Glassfish server (version 4.0, to match my target environment). I got the gist of how to use the @Schedule annotation from this SO question and the gist of Lock annotations from this SO question.


The Resolution:

Singleton classes default to @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) and all their methods default to @Lock(LockType.WRITE). When execution enters a LockType.WRITE method it causes the execution of any other methods to wait. You can override this at the class level with @ConcurrencyManagement(ConcurrencyManagementType.BEAN) or by annotating all methods that are suitable for concurrent access with @Lock(LockType.READ).


Answer:

Using threads explicitly is generally no good in a EJB environment.

They populate/polute the server and might come out of control, causing problems for the server, because they are not controlled by the EJB container.

A better solution is to use the @Asynchronous annotation on a method of the singleton for example. With this you can start asynchronous tasks without problems for the server.

Edit: Reason, why the doGet() method is blocking:

When the Scheduler invokes the EJB's run() method, it will lock the Singleton EJB as a whole, as write protection is the default behavior. After entering run() the Task object's run() method will be called invoking Thread.sleep(...). Meanwhile the EJB's getState() method will be blocked until sleeping is finished, thus blocking the doGet() method of the WebServlet.

As the OP says in a later comment, this situation can be overcome by using an annotation @Lock(LockType.READ) above the Singleton's run() method (and above getState()).

Question:

I'm building an REST API with javaEE. I'm using TomEE as application server. I have a Singleton JPA DAO to deal with Postgres database and Stateless service to provide methods to my RESTfull class, which has GET,POST and DELETE methods. Until now, I'm using rest assured to test my url routes. Everything is working fine, but I wanted to stress my system, so I did this:

  Runnable r1 = () -> {
        for (int i = 0; i < 10; i++) {
            RegisterAndLogService service = new RegisterAndLogService();
            //lots of service calls
        }
    };

    Runnable r2 = () -> {
        for (int i = 0; i < 10; i++) {
            RegisterAndLogService service2 = new RegisterAndLogService();
            //lots of service calls
        }
    };
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);
    t1.start();
    t2.start();

But when second iteration on one of my threads would begin, I got this:

java.lang.IllegalStateException: Transaction already active

How can I pile up dao resquests and deal with them properly one at a time waiting current transaction to finish? Can EJB/JPA somehow be involved into this? Into saving asked requests and dealing with them asap?


Answer:

It is difficult to understand what you are doing here, and whether the problem you are asking about is in the test code or the API under test ... or the stuff behind the API.

But if you are getting a "Transaction already active" that means that something is doing something like:

  • trying to use a single JPA transaction manager with multiple threads (don't),
  • trying to do multiple simultaneous transactions on the same thread (don't), or
  • not cleaning up (committing or rolling back) transactions.

In the last case, look for cases where you can "escape" from a code region responsible for a transaction via an exception without rolling it back.

I would advise that you review the documentation on JPA that you have been using to make sure that you understand the relationships between transactions, transaction managers and threads.


I believe my case is the first one - trying to use a single JPA transaction manager with multiple threads. Is there any design pattern or good practice about keeping a single JPA transaction manager while have lots of instances of stateless beans being requested?

The only way that works is for each thread to have its own transaction manager. Either each thread must create (and release) its own TM programatically, or you rely on the framework to do this; e.g. as instructed by various annotations.

TM objects are designed to be light-weight (i.e. cheap to instantiate) and non-thread-safe. You shouldn't share them across threads1 and you shouldn't need to recycle them.


1 - ... unless you have a single JPA transaction that needs to span multiple threads. For that, there are "ways to do it".

Question:

I have this EJB deployed to Glassfish 4 (Java EE 7):

import javax.ejb.EJB;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Schedule;
import javax.ejb.Singleton;

@Singleton
@Lock(LockType.WRITE) // WRITE is default, but here for emphasis
public class SingletonBean {

    @EJB
    SingletonBean self;

    @Schedule(second="*/3", minute="*", hour="*")
    public void test_automatic_timer() throws InterruptedException {
        System.out.println("test_automatic_timer()");
        self.test();
    }

    public void test() {
        System.out.println("test()");
    }

}

I expected this to deadlock. When the timer calls test_automatic_timer, it obtains the WRITE lock. The call to self.test() should wait forever for the lock to be released, but in the logs I have:

Info:   test_automatic_timer()
Info:   test()
Info:   test_automatic_timer()
Info:   test()

Why isn't this working the way I expected?

p.s. This isn't entirely academic. I want to do a self call so that I can get a new container-managed transaction, but I want to make sure I understand the synchronization better first.


Confirming Steve's answer

Steve's answer is correct. To confirm this, I logged the thread ID and saw that they are the same. I also wanted to confirm that the lock was working, so I rewrote the method bodies as follows:

@Schedule(second="*/3", minute="*", hour="*")
public void test_automatic_timer() throws InterruptedException {
    System.out.println("test_automatic_timer()");
    System.out.println(Thread.currentThread());
    self.test();
    Thread.sleep(10_000);
}

@Asynchronous
public void test() {
    System.out.println("test()");
    System.out.println(Thread.currentThread());
}

If this works as expected, the asynchronous call to test will be blocked for ten seconds until test_automatic_timer is finished. If it doesn't work, test will be executed immediately. The logs show:

Info:   test_automatic_timer()
Info:   Thread[__ejb-thread-pool11,5,main]
// 10 second pause...
Info:   test()
Info:   Thread[__ejb-thread-pool12,5,main]

So it works.


Answer:

This code is not deadlocking because the call to test() is being made in the same (timer execution) thread.

That said I think that at least some of the behaviour when self injecting a a singleton like this may be undefined. What will happen if you introduce an @PostConstruct method that references self?

Your bean name is a misnomer because @Singleton beans are stateful.

Anyway, it is probably safer to do something like:

@Singleton
@Lock(LockType.WRITE) // WRITE is default, but here for emphasis
public class SingletonBean {

    @Resource
    private SessionContext sessionContext;

    @Schedule(second="*/3", minute="*", hour="*")
    public void test_automatic_timer() throws InterruptedException {
        System.out.println("test_automatic_timer()");
        sessionContext.getBusinessObject(StatelessSessionBean.class).test();
    }

    @Transactional(REQUIRES_NEW)
    public void test() {
        System.out.println("test()");
    }

}

And this is indeed the way to self invoke an EJB with a new transaction.