java session 安全_java – 了解Goetz关于HttpSession线程安全性的文章

你的代码仍然不是线程安全的:

ShoppingCart cart = cartRef.get();

if (cart == null) {

cart = new ShoppingCart(...);

session.setAttribute("shoppingCart",new AtomicReference(cart));

}

这是因为两个线程都可以获得一个零车,创建新的购物车对象,并将它们插入到会话中.其中一个将“赢”,意味着将设置未来请求使用的对象,但另一个将 – 为此请求 – 使用完全不同的购物车对象.

要使这个线程安全,您需要执行类似的操作,遵循引用的文章中的成语:

while (true) {

ShoppingCart cart = cartRef.get();

if (cart != null) {

break;

}

cart = new ShoppingCart(...);

if (cartRef.compareAndSet(null,cart))

break;

}

使用上述代码,如果使用相同HttpSession的两个线程同时进入while循环,则不会导致它们使用不同的cart对象的数据竞争.

为了解决Brian Goetz在文章中没有解决的问题的一部分,即如何将AtomicReference首先引入到会话中,那么有一个简单而且可能(但不是保证)线程安全的方法来做到这一点.也就是说,实现一个会话监听器,并将空的AtomicReference对象放入sessionCreated方法的会话中:

public class SessionInitializer implements HttpSessionListener {

public void sessionCreated(HttpSessionEvent event){

HttpSession session = event.getSession();

session.setAttribute("shoppingCart",new AtomicReference());

}

public void sessionDestroyed(HttpSessionEvent event){

// No special action needed

}

}

对于每个会话,这个方法将被调用一次,只有当它被创建时,所以这是执行会话所需的任何初始化的适当的地方.不幸的是,Servlet规范并不要求在侦听器中调用sessionCreated()并调用service()方法之间发生关系.所以这显然不能保证线程安全,并且可能会在不同Servlet容器之间的行为有所不同.

因此,如果给定的会话一次只能有少于几次飞行中的请求,这是不够安全的.最终,在这种情况下,您需要使用某种类型的锁来初始化会话.你可以这样做:

HttpSession session = request.getSession(true);

AtomicReference cartRef;

// Ensure that the session is initialized

synchronized (lock) {

cartRef = ()session.getAttribute("shoppingCart");

if (cartRef == null) {

cartRef = new AtomicReference();

session.setAttribute("shoppingCart",cartRef);

}

}

上述代码执行完毕后,会话被初始化. AtomicReference保证在会话中,并以线程安全的方式.您可以更新同一个同步块中的购物车对象(并将AtomicReference全部放在一起 – 只需将购物车本身放入会话),也可以使用前面显示的代码更新AtomicReference.哪个更好取决于需要做多少初始化,执行此初始化需要多长时间,是否在同步块中执行所有操作会对性能造成太大的损害(最好用分析器确定,而不是猜测),等等.

通常,在我自己的代码中,我只使用一个同步块,不要使用Goetz的AtomicReference技巧.如果我曾经确定同步在我的应用程序中引起了一个活跃的问题,那么我可能通过使用像AtomicReference技巧这样的技巧,从同步块中移除一些更昂贵的初始化.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值