Java Servlet中的静态变量行为

我正在开发一个java servlet,在运行时,在新线程中启动不同的对象方法。 这些线程应该访问描述特定servlet实例的变量,比如jobId。 出于这个原因,我将jobId变量声明为static。 servlet构造函数正在为每个servlet实例(调用)计算此值。 如果servlet同时被调用几次,我就会徘徊,静态jobId变量在调用之间共享,这意味着一些线程将获得错误的jobId,或者每次调用都计算一次 – 所以线程是特定的servlet启动将使用为此特定servlet计算的jobId(这是我希望它工作的方式)。 有任何想法吗? 非常感谢!

servlet仅在webapp启动时创建一次,并在所有请求之间共享。 静态与否,每个类/实例变量将在所有请求/会话之间共享。 您不希望将请求/会话范围数据分配给它们。 而是声明/将它们指定为方法局部变量。 例如

 public class MyServlet extends HttpServlet { private static Object thisIsNotThreadsafe; private Object thisIsAlsoNotThreadsafe; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object thisIsThreadsafe; thisIsNotThreadsafe = request.getParameter("foo"); // BAD! Shared among all requests. thisIsAlsoNotThreadsafe = request.getParameter("foo"); // BAD! Shared among all requests. thisIsThreadsafe = request.getParameter("foo"); // Good. } } 

存在遗留和已弃用的 SingleThreadModel接口,您可以让servlet在每个请求期间强制创建。 但这是一个糟糕的设计,并且不必要地昂贵。 这也是它被弃用的原因。

也可以看看:

  • Servlet实例和multithreading
  • servlet如何工作?

static表示每个实例都将访问相同的值。
因此,连接到servlet的每个用户都将访问相同的值。 当两个或更多用户连接在一起时,您的jobId可能会出错。

您必须为每个连接获取自己的值并将其存储在其他位置。


资源:

  • servlet中的静态变量 – 我们什么时候可以使用?

在同一主题上:

  • 在servlet和webservice之间共享静态对象

静态变量是共享的。 静态变量不属于任何一个实例,所有类的实例都可以访问它们。 当您使用构造函数(用于创建一个对象(该类的一个实例))时,在构造函数中设置静态变量通常没有意义,因为它超出了您正在创建的对象的范围。

至于什么可行,你可以将jobId放在HttpSession中,然后每个用户都有自己的副本。

Servlet的实例化策略没有在servlet规范中定义(据我所知,anywho),但通常的行为似乎是每个servlet配置只创建一个实例。 因此,在您的情况下,每个请求都将使用相同的变量。

如果我是你,我会考虑将jobId作为参数发送给你正在运行线程的Runnable 。 例如,取而代之的是:

 public class HelloWorld extends HttpServlet { private static long jobId; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { jobId = Long.parseLong(request.getParameter("jobid"); new Thread(new Worker()).start(); } static class Worker implements Runnable { @Override public void run() { doSomethingWith(jobId); } } } 

像这样重构静态变量:

 public class HelloWorld extends HttpServlet { // private static long jobId; -- delete, no longer needed public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long jobId = Long.parseLong(request.getParameter("jobid"); // local variable new Thread(new Worker(jobId)).start(); // send jobId as parameter } static class Worker implements Runnable { private final long jobId; // non-static; every instance has one public Worker(long jobId) { // allow injection of jobId this.jobId = jobId; } @Override public void run() { doSomethingWith(jobId); // use instance variable instead of static } } } 

更容易阅读,没有并发问题 – 纯粹的胜利。