Java Servlet中的静态变量行为

时间:2010-09-02 12:01:53

标签: java multithreading servlets static

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

4 个答案:

答案 0 :(得分:29)

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

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在每个请求期间强制创建。但这是一个糟糕的设计,并且不必要地昂贵。这也是它被弃用的原因。

另见:

答案 1 :(得分:2)

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

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


资源:

关于同一主题:

答案 2 :(得分:2)

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

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

答案 3 :(得分:2)

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

}

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