我要澄清的第一件事是,我知道Servlet是单实例多线程模型。 Container维护在实例上,并为每个要处理的请求创建多个线程,并且所有线程在同一个servlet实例上工作。此外,我们不应该在servlet中维护状态,因为它会导致多线程/并发问题。凉!!如果状态(servlet的成员)本身是线程安全的呢?如下例所示
public class MyCrazyServlet extends HttpServlet {
StringBuffer s1 = new StringBuffer("stackoverflow");
static StringBuffer s2 = new StringBuffer("stackexchange");
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String s3 = "I'm safe";
HttpSession crazySession = request.getSession();
//more stuff here
}
}
在上面的代码片段中,我假设除了crazySession局部变量(HttpSession实例)之外的所有其他内容(s1,s2和s3)都是线程安全的
如果我的理解错误,请更正
答案 0 :(得分:3)
在给定的代码段中,s2
永远不会被修改,因此它必须是安全的。但现在这不是真正有趣的用例,是吗?
StringBuffer
是线程安全的,因为如果两个不同的线程同时修改它,一个调用将等待另一个调用结束,这样两个调用都将完全执行而不会互相混淆。
请考虑以下代码段:
// name is retrieved from the calling session
public void addName (String name) {
// s2 is defined as:
// static StringBuffer s2 = new StringBuffer("stackexchange")
// by the OP
s2.append(name);
}
如果您(JavaHopper)和我(Mureinik)同时调用此函数,则可以保证内容不会被扰乱。
根据呼叫的确切时间和上下文切换,s2
将包含"stackexchangeJavaHopperMureinik"
或"stackexchangeMureinikJavaHopper"
。
但这是陷阱 - 你需要非常,非常小心你的电话。通常情况下,您需要链接多个呼叫,例如:
// name is retrieved from the calling session
public void addName (String name) {
// s2 is defined as:
// static StringBuffer s2 = new StringBuffer("stackexchange")
// by the OP
s2.append("[").append(name).append("]");
}
在此示例中,每个append
都是不同的呼叫。因此,上述两个并发调用可能会产生有效的结果,如"stackexchange[JavaHopper][Mureinik]"
,但可能会产生类似"stackexchange[JavaHopper[Mureinik]]"
的内容。
总结一下:小心。要非常小心。根据代码的复杂程度,最好自己处理同步。