Here my conclusion on this question:
"Vanilla" Thread in servlet
Here a sample code of a successful execution done after response sent:
protected void doPost(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
final long startTime = System.currentTimeMillis(); //Start time to compare easily
// MY ASYNC JOB
Thread t1 = new Thread(new Runnable() {
public void run()
{
try {
Thread.sleep(10000);
System.out.println("Long operation done. / " + (System.currentTimeMillis() - startTime));
} catch (InterruptedException e) {
e.printStackTrace();
}
}});
t1.start();
// END OF MY ASYNC
// Servlet code here
System.out.println("Will send the response. / " + (System.currentTimeMillis() - startTime));
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
Result: I received the response in 17ms in Postman
Will send the response. / 1
Long operation done. / 10011
Spawn thread in a servlet is against Java EE spec and EJB doesn't work inside. See here or here. Use threads this way can lead to thread starvation. This is not allowed on every server (Tomcat doesn't prevent this).
Scalability is contractual and it is really interesting to know all options for me and readers. And I do not know on what server I will host my webapp !
ManagedExecutorService
ManagedExecutorService is part of Java EE 7. In my case, the project target a Java EE 6 environment so I used ExecutorService instead. Earlier I faced an issue: I can not access body of the request in my async, and I find this:
Asynchronous Request Body read [...] concepts introduced in Servlet 3.1
But Servlet 3.1 is Java EE 7 too. So my runnable constructor ask for the request body as a String.
Here a sample code for ServletContextListener:
public void contextInitialized(ServletContextEvent event) {
//Executor
executor = Executors.newCachedThreadPool();
//Init Context
app = event.getServletContext();
app.setAttribute("executor", executor);
}
//Do not forget to implements contextDestroyed !
public void contextDestroyed(ServletContextEvent event) {
try {
executor.shutdown();
while(!executor.awaitTermination(10, TimeUnit.SECONDS)){
System.out.println("executor.awaitTermination");
};
} catch (InterruptedException e) {
e.printStackTrace();
}
}
And my servlet:
protected void doPost(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
final long startTime = System.currentTimeMillis(); //Start time to compare easily
//Get my executor service and run a new async task
ExecutorService serv = (ExecutorService) this.getServletContext().getAttribute("executor");
serv.execute(new testAsync(startTime));
// Servlet code here
System.out.println("Will send the response. / " + (System.currentTimeMillis() - startTime));
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
//My runnable
private class testAsync implements Runnable{ //Use Callable for Java 7+
private long startTime;
//Prior to Servlet 3.1, you have to give the request body instead of using asyncContext
public testAsync(long pstart){
this.startTime = pstart;
}
@Override
public void run(){
try {
Thread.sleep(10000);
System.out.println("Long operation done. / " + (System.currentTimeMillis() - this.startTime));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
This example works and seems to be the best solution for me because I have to do multithreading in my async task. I use Tomcat for dev but if you use something else, you have to use ManagedExecutorService because it could prevents you to start thread in a servlet.
I am also very surprised to do not find a simple quick example on stackoverflow. I was able to code it thanks to this article.
Edit: I was not aware of JMS at this time and will work on it to see if it fit my problem