Search code examples
javajakarta-eeejb

Arguments overridden in managed callable tasks in Java EE


I have several container managed callable tasks that are invoked with invokeAll. I need to pass arguments to each of these tasks, and since I'm getting instances instead of creating objects manually (this is a requirement) I cannot pass arguments in a constructor.

I'm using setters in the task to set values, but for some reason when I have multiple tasks the last value overrides the previous one.

Given this task:

@Stateless
@LocalBean
public class MyTask implements Callable<String> {

    private String value;

    @Override
    public String call() throws Exception {
        System.out.println("MyTask called with value = " + value);
        return "MyTask called";
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

Called with this Test class:

public class Test {

    @Inject
    Instance<MyTask> myTaskInstance;

    @Resource
    private ManagedExecutorService executor;

    public void test() throws InterruptedException, ExecutionException {

        List<Callable<String>> tasks = new ArrayList<>(); 

        MyTask task1 = myTaskInstance.get();
        task1.setValue("VAL1");
        tasks.add(task1);

        MyTask task2 = myTaskInstance.get();
        task2.setValue("VAL2");
        tasks.add(task2);

        List<Future<String>> taskResults = null;
        taskResults = executor.invokeAll(tasks);

        List<String> results = new ArrayList<>(); 

        for(Future<String> taskResult : taskResults) {
                results.add(taskResult.get());
        }

    }

}

The result is (note VAL2 twice):

13:04:49,044 INFO [stdout] (EE-ManagedExecutorService-default-Thread-3) MyTask called with value = VAL2

13:04:49,045 INFO [stdout] (EE-ManagedExecutorService-default-Thread-4) MyTask called with value = VAL2

What is wrong with this code? How to fix this?

UPDATE After changing the bean to @Stateful these are the task instances right before invokeAll

enter image description here

enter image description here


Solution

  • This is perfectly normal.

    A @Stateless bean is created in multiple instances, depending on your server pool configuration.
    So the same instance is re-used from the pool.

    Per definition a @Stateless bean cannot maintain a state.
    Use a @Stateful bean instead.