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 } } }
更容易阅读,没有并发问题 – 纯粹的胜利。