Servlets适合复合操作吗?
Are Servlets suitable for composite operations?
Servlet 是非线程安全的,状态可能会在不同请求的方法调用之间丢失。
但是我可以在 单个 请求期间保持自己的 Servlet 方法之间的状态安全地实现复合操作吗?
像这样:
public class MyServlet extends HttpServletRequest {
private String var;
void addH() {
var += "h";
}
void addI() {
var += "i";
}
void doGet(...) {
addH();
addI();
// var = "hi"?
}
}
在这种情况下 var
是否包含正确的值,即使是并发请求?换句话说,它是否像 EJB 中的无状态 Bean 一样工作?
public class MyServlet extends HttpServletRequest {
private String var = "";
void addH() {
var += "h";
}
void addI(long dontAnswerBefore) {
while(System.currentTimeMillis() < dontAnswerBefore) {
// Do nothing
}
var += "i";
}
void doGet(...) {
long now = System.currentTimeMillis();
addH();
addI(now + 10_000);
resp.write(var);
}
}
这应该让您有 10 秒的时间在两个选项卡或两个不同的浏览器中发出两个请求。
不,你不能。正如您所说,servlet 不是线程安全的。请求所在的位置没有受保护的 "space"。因此多个线程(以及请求)可以同时命中 var
。如果你想要这样一个受保护的"space",你需要同步doGet()
(这当然会破坏并发性)或者做一些像使用ThreadLocal
这样的事情,这样每个线程(以及请求)都会有它自己单独的实例范围状态副本。
如果您不需要状态在请求之外持续存在,您可以在 doGet()
中创建状态并将其传递给其他方法:
void doGet(...) {
StringBuilder var = new StringBuilder();
addH(var);
addI(var);
resp.write(var.toString());
}
void addH(StringBuilder var) {
var.append('h');
}
void addI(StringBuilder var) {
ver.append('i');
}
Servlet 是非线程安全的,状态可能会在不同请求的方法调用之间丢失。
但是我可以在 单个 请求期间保持自己的 Servlet 方法之间的状态安全地实现复合操作吗?
像这样:
public class MyServlet extends HttpServletRequest {
private String var;
void addH() {
var += "h";
}
void addI() {
var += "i";
}
void doGet(...) {
addH();
addI();
// var = "hi"?
}
}
在这种情况下 var
是否包含正确的值,即使是并发请求?换句话说,它是否像 EJB 中的无状态 Bean 一样工作?
public class MyServlet extends HttpServletRequest {
private String var = "";
void addH() {
var += "h";
}
void addI(long dontAnswerBefore) {
while(System.currentTimeMillis() < dontAnswerBefore) {
// Do nothing
}
var += "i";
}
void doGet(...) {
long now = System.currentTimeMillis();
addH();
addI(now + 10_000);
resp.write(var);
}
}
这应该让您有 10 秒的时间在两个选项卡或两个不同的浏览器中发出两个请求。
不,你不能。正如您所说,servlet 不是线程安全的。请求所在的位置没有受保护的 "space"。因此多个线程(以及请求)可以同时命中 var
。如果你想要这样一个受保护的"space",你需要同步doGet()
(这当然会破坏并发性)或者做一些像使用ThreadLocal
这样的事情,这样每个线程(以及请求)都会有它自己单独的实例范围状态副本。
如果您不需要状态在请求之外持续存在,您可以在 doGet()
中创建状态并将其传递给其他方法:
void doGet(...) {
StringBuilder var = new StringBuilder();
addH(var);
addI(var);
resp.write(var.toString());
}
void addH(StringBuilder var) {
var.append('h');
}
void addI(StringBuilder var) {
ver.append('i');
}