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