Consider the following setup:
1. TPETestClass.java
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/")
public class TPETestClass {
//ThreadPoolExecutor - TPE
private ThreadPoolExecutor exec = new ThreadPoolExecutor(1, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
@GET
@Path("task")
@Produces(MediaType.TEXT_PLAIN)
public String startTask() {
RunnableTestClass rtc = new RunnableTestClass();
exec.execute(rtc);
return String.format("There are currently %1$d tasks running\n", exec.getTaskCount());
}
}
class RunnableTestClass implements Runnable {
@Override
public void run() {
for (int i =0; i < 5; i ) {
System.out.println(i " seconds have passed.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2. EmbeddedServer.java
import java.net.URI;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import com.sun.net.httpserver.HttpServer;
public class EmbeddedServer {
public void start()
{
URI baseUri = UriBuilder.fromUri("http://localhost/").port(8080).build();
ResourceConfig config = new ResourceConfig(TPETestClass.class);
HttpServer server = JdkHttpServerFactory.createHttpServer(baseUri, config);
}
}
And finally 3. RunTasks.java
public class RunTasks {
public static void main(String[] args) {
EmbeddedServer es = new EmbeddedServer();
es.start();
}
}
First, I run the main method in RunTasks to start up the server on my localhost. Then, I visit the endpoint http://localhost:8080/task multiple times, which should queue up multiple threads in the ThreadPoolExecutor. The behavior I want is for the number of displayed tasks to increase as I visit the link more times. However, this does not happen. Instead, the tasks remain at 1.
Further, the printed statements to console become out of order, as below:
0 seconds have passed.
1 seconds have passed.
0 seconds have passed.
2 seconds have passed.
1 seconds have passed.
0 seconds have passed.
3 seconds have passed.
2 seconds have passed.
1 seconds have passed.
4 seconds have passed.
3 seconds have passed.
What I have tried is to make the ThreadPoolExecutor a static variable. This works as I get the following results (I visited the link 5 times):
With the console output:
0 seconds have passed.
1 seconds have passed.
2 seconds have passed.
3 seconds have passed.
4 seconds have passed.
0 seconds have passed.
1 seconds have passed.
2 seconds have passed.
3 seconds have passed.
4 seconds have passed.
...
Here are my questions.
- Why do I have to make the ThreadPoolExecutor static in order for it to behave as expected? Shouldn't it behave like this even without the static variable? Are multiple instances of TPETestClass somehow created?
- Why do the tasks always remain at 1 and seem to execute alongside one another (based on what I am seeing in the console).
- Is there a better way to get this desired behavior rather than making a static variable?
CodePudding user response:
- Why do I have to make the
ThreadPoolExecutor
static in order for it to behave as expected? Shouldn't it behave like this even without the static variable? Are multiple instances ofTPETestClass
somehow created?
No it shouldn't. There is a new instance of TPETestClass
for each request.
According to Chapter 3. JAX-RS Application, Resources and Sub-Resources:
"By default the life-cycle of root resource classes is per-request which, namely that a new instance of a root resource class is created every time the request URI path matches the root resource."
- Why do the tasks always remain at 1 and seem to execute alongside one another (based on what I am seeing in the console).
It is not clear which version of the code you are talking about. But assuming you mean the version in which exec
is an instance variable, you will get a new ExecutorService
for each request and each one only ever executes one task.
- Is there a better way to get this desired behavior rather than making a static variable?
The link above suggests / implies two alternatives:
- Get your
Application
object to create a singleton instance ofTPETestClass
- Apply the
@Singleton
annotation to theTPETestClass
class. There are examples further down the linked page.