为什么 webservice 调用使用的 ThreadPoolExecutor 不排队多个线程?

Why does ThreadPoolExecutor used by a webservice call not queue multiple threads?

考虑以下设置:

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);
    
    }

}

最后 3。 RunTasks.java

public class RunTasks {
    public static void main(String[] args) {
    EmbeddedServer es = new EmbeddedServer();
    es.start();
    }
}

首先,我 运行 RunTasks 中的主要方法在我的本地主机上启动服务器。然后,我多次访问端点 http://localhost:8080/task,这应该在 ThreadPoolExecutor 中排队多个线程。我想要的行为是随着我访问 link 次数的增加而增加显示的任务数。但是,这不会发生。相反,任务保持在 1。

此外,打印到控制台的语句变得乱序,如下所示:

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.

我尝试过将 ThreadPoolExecutor 设为静态变量。这是有效的,因为我得到以下结果(我访问了 link 5 次):

控制台输出:

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.
...

这是我的问题。

  1. 为什么我必须将 ThreadPoolExecutor 设为静态才能使其按预期运行?即使没有静态变量,它也不应该像这样吗?是否以某种方式创建了 TPETestClass 的多个实例?
  2. 为什么任务总是保持在 1 并且似乎一个接一个地执行(根据我在控制台中看到的内容)。
  3. 有没有比创建静态变量更好的方法来获得所需的行为?
  1. 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?

不应该。每个请求都有一个 TPETestClass 的新实例。

根据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."


  1. Why do the tasks always remain at 1 and seem to execute alongside one another (based on what I am seeing in the console).

不清楚你说的是哪个版本的代码。但是假设您指的是 exec 是实例变量的版本,您将为每个请求获得一个新的 ExecutorService 并且每个请求只执行一个任务。


  1. Is there a better way to get this desired behavior rather than making a static variable?

上面的 link 建议/暗示两种选择:

  • 获取您的 Application 对象以创建 TPETestClass
  • 的单例实例
  • @Singleton 注释应用于 TPETestClass class。 linked 页面下方有示例。