william0218 2009-05-13 15:38
浏览 264
已采纳

请教一下,关于Servlet的线程安全的问题

Servlet是线程不安全的,因为默认情况下是只实例化一个实例出来,然后,为每一个请求分配一个线程来运行,我看到有些书中说,可以把访问共享数据的代码同步下,就可以实现线程安全了,但是我对此有疑问。会话不是线程安全的,因为如果我们同时打开两个浏览器窗口,那么实际上就是两个请求,两个线程,两个线程访问同一个会话,就有线程安全问题,比如我们对一个会话设置属性:
...
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{
...
Session session = request.getSession();
String username = request.getParameter("username");
synchronized(session) {
session.setAttribute("username", username);
}
...
}
...

我们在jsp页面用到这个"username"属性:

<%
String username = session.getAttribute("username");
%>
Welcome <%= username %> !

那么我们是否要对上面的代码也同步呢? 变成这样:

<%
String username = null;
synchronized(session) {
username = (String)session.getAttribute("username");
}
%>
Welcome <%= username %> !

这样就能实现线程安全了吗?
虽然我们对访问会话的代码进行了同步,在同一时刻,只能有一个线程对会话访问,但是,是否会出现这种情况呢?
有两个线程A,B,线程A先运行,B后运行
线程A-->锁定会话-->访问会话,设置属性username值为"aaa"-->解锁-->进入jsp-->锁定会话-->访问会话的username属性,这时的username属性被线程B覆盖了,所以得到"bbb"-->解锁-->继续执行其他指令。
线程B-->等待解锁-->锁定同一会话,设置username属性值为"bbb"-->解锁-->进入jsp-->锁定会话-->访问会话的username属性得到"bbb"-->解锁-->继续执行其他指令。
简单说,就是在线程A解锁了session之后,线程B马上就进入了session,覆盖了线程A的username属性为"bbb",然后线程A在jsp页面里得到就是"bbb",而非"aaa",我这样理解对不对呢?
请明白的朋友不吝赐教,谢谢!

[b]问题补充:[/b]

我不知道怎么回复我的问题,所以只好用问题补充来作为回帖了。
回复alexma:
我觉得对每一个不同的请求,request对象是不同的,但是用这个方法:
request.getSession();
并非是每次都创建一个新的session对象,如果已经有一个session对象存在,并且客户端浏览器支持cookie的话,取出来就是原来session对象的引用,那么是有可能两个request对象获得同一个session对象的引用,比如,我在自己的机器上打开FireFox3访问JavaEye论坛,然后又打开一个tab页面,也访问JavaEye,这种情况下,两个不同的request,却会与同一个session对象联系。

[b]问题补充:[/b]

回复alexma:
你说的我理解,但是我的意思是说,有两个[b]线程[/b],非进程,与同一个session对象进行联系的话,像我上面那种写法(同步对session进行操作的代码),是否仍然存在线程安全问题?不是讨论这样是否能模拟让两个用户出现冲突的情况,而是讨论的是线程安全的问题。
谢谢你的回复。

[b]问题补充:[/b]

回复alexma:
谢谢你的回复。我会去看的。

  • 写回答

4条回答 默认 最新

  • alexma919 2009-05-14 09:47
    关注

    你可以用 FF 看一下 cookie ,里边有一个 jsessionid 的值。你在服务器端用 request.getSession() 取 session 的时候,实际上就是用这个 id 去拿 session 对象。你可以想象在 server 端有个很大的 hash map ,里边的 key 就是这个 id ,value 就是 session 对象。至于你说你在 FF 里,两个 tab 取到的是同一个 session ,这是当然的,因为你在同一个浏览器进程里,对于两个 tab ,他们对应的 jsessionid 是一样的,你可以查看一下。

    对于两个真正的用户,不可能用同一个机器的同一个浏览器,所以他们不可能用到同一个 jsessionid ,固此不会出现冲突。

    如果你用两个不同的浏览器测试,就不会出现这个问题。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!
  • ¥15 永磁直线电机的电流环pi调不出来
  • ¥15 用stata实现聚类的代码
  • ¥15 请问paddlehub能支持移动端开发吗?在Android studio上该如何部署?
  • ¥20 docker里部署springboot项目,访问不到扬声器
  • ¥15 netty整合springboot之后自动重连失效