Java Servlet 中的静态变量行为

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3626863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 02:51:55  来源:igfitidea点击:

Static Variables Behaviour in a Java Servlet

javamultithreadingservletsstatic

提问by Che

I am developing a java servlet that while running, starts different objects methods in new threads. Those threads should access a variable that describes the specific servlet instance, say jobId. For this reason, i declared the jobId variable as static. The servlet constructor is calculating this value for each servlet instance (call). I was wandering if the servlet is called few times at the same time, the static jobId variable is shared between the calls, which means that some threads will get the wrong jobId, or it is calculated once for each call- so the threads that a specific servlet started will use the jobId calculated for this specific servlet (which is the way i want it to work). Any ideas? Thanks a lot!

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

回答by Colin Hebert

staticmeans that every instance will access to the same value.
So every user connected to the servlet will access to the same value. Your jobId will be probably wrong when 2 users or more are connected together.

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

You have to get your own value a each connection and store it somewhere else.

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



Resources :

资源 :

On the same topic :

在同一主题上:

回答by Nathan Hughes

Static variables are shared. Static variables don't belong to any one instance, they are accessible by all instances of the class. When you are using a constructor, that is used to create one object (one instance of the class), setting a static variable in a constructor typically doesn't make sense because it's something that is outside the scope of the object you're creating.

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

As for what would work, you could put the jobId in the HttpSession and then each user would have their own copy of it.

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

回答by BalusC

A servlet is created only once on webapp's startup and shared among all requests. Static or not, every class/instance variable is going to be shared among all requests/sessions. You would not like to assign request/session scoped data to them. Rather declare/assign them as methodlocal variable. E.g.

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

There exist the legacy and deprecatedSingleThreadModelinterface which you can let your servlet implement to force creation during every request. But this is a bad design and unnecessarily expensive. That's also why it's deprecated.

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

See also:

也可以看看:

回答by gustafc

The instantiation policy for servlets is not defined in the servlet spec (as far as I can remember, anywho) but the usual behavior seems to be to create only one instance per servlet configuration. So, in your case, every request would use the same variable.

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

If I were you, I'd consider to send the jobId as a parameter to the Runnables you're running the threads with. For example, in stead of this:

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

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

}

Refactor away the static variables like this:

像这样重构静态变量:

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

}

Easier to read, no concurrency problems - pure win.

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