现在我的问题是,Spring Session是否有任何功能来处理会话条目中的竞争条件?
或者Java中的任何其他库/框架!
解决方法
RequestMappingHandlerAdapter.setSynchronizeOnSession-boolean-
这将使每个Controller方法在会话存在时同步.
HttpSession.setAttribute是线程安全的.但是getAttribute后跟setAttribute必须手动安全.
synchronized(session) { session.setAttribute("foo","bar"); session.getAttribute("foo"); }
在spring会话bean的情况下可以做同样的事情.
synchronized(session) { //do something with the session bean }
#编辑
如果多个容器具有普通的spring会话bean,则必须使用粘性会话.这将确保一个会话状态存储在一个容器中,并且每次请求相同会话时都访问该容器.这必须在BigIP cookie之类的帮助下在负载均衡器上完成.休息将与单个会话存在单个容器的方式相同,因此锁定会话就足够了.
如果您希望跨实例使用会话共享,则对容器(例如Tomcat和Jetty)提供支持
出于同样的目的,您可以尝试使用Spring Session.使用Redis进行配置非常简单.由于Redis是单线程的,因此可确保以原子方式访问条目的一个实例.
以上方法是非侵入性的.数据库和基于Redis的方法都支持transactions.
但是,如果您想要更好地控制分布式状态和锁定,可以尝试使用分布式数据网格,如Hazelcast和Gemfire.
我亲自与Hazelcast合作,它确实提供了methods to lock entries made in the map.
#EDIT2
虽然我认为处理事务应该足以满足Spring Session和Redis,以确保您需要分布式锁定.必须从Redis本身获取锁定对象.由于Redis是单线程的,因此个人实现也可以使用像INCR这样的东西
算法将如下所示
//lock_num is the semaphore/lock object lock_count = INCR lock_num while(true) { if(lock_count != 1) { DECR lock_num } else { break } wait(wait_time_period) } //do processing in critical section DECR lock_num
但是,幸运的是,Spring已经通过RedisLockRegistry提供了这种分布式锁实现.更多文档于usage is here.
如果您决定使用没有弹簧的普通Jedis,那么这里是Jedis的分布式锁:Jedis Lock.
//from https://github.com/abelaska/jedis-lock Jedis jedis = new Jedis("localhost"); JedisLock lock = new JedisLock(jedis,"lockname",10000,30000); lock.acquire(); try { // do some stuff } finally { lock.release(); }
这两个都应该像Hazelcast锁定一样工作.