Meh*_*ran 7 java session locking spring-session
由于REST服务的远程调用特性,它们处于不断变为竞争状态的状态.比赛的日常资源之一是会议.为了实用,您需要能够在流程开始时锁定资源,并在完成任务后将其提升.
现在我的问题是,Spring Session是否有任何功能来处理会话条目中的竞争条件?
或者Java中的任何其他库/框架!
如果您使用 Spring 控制器,那么您可以使用
RequestMappingHandlerAdapter.setSynchronizeOnSession-boolean-
这将使每个控制器方法在存在会话时同步。
HttpSession.setAttribute是线程安全的。然而getAttribute,随后setAttribute必须手动确保胎面安全。
synchronized(session) {
session.setAttribute("foo", "bar");
session.getAttribute("foo");
}
Run Code Online (Sandbox Code Playgroud)
对于 Spring 会话 bean 也可以这样做。
synchronized(session) {
//do something with the session bean
}
Run Code Online (Sandbox Code Playgroud)
#编辑
如果多个容器具有普通的 spring 会话 bean,则必须使用sticky sessions. 这将确保一个会话状态存储在一个容器上,并且每次请求同一会话时都会访问该容器。这必须在负载均衡器上借助诸如BigIP cookies. 休息的工作方式与单个会话相同,存在单个容器,因此锁定会话就足够了。
如果您想跨实例使用会话共享, Tomcat和Jetty等容器提供支持
这些方法使用后端数据库或其他一些持久性机制来存储状态。
出于同样的目的,您可以尝试使用Spring Session。使用 .config 进行配置很简单Redis。由于 Redis 是单线程的,因此它确保以原子方式访问条目的一个实例。
上述方法都是非侵入性的。基于数据库和 Redis 的方法都支持事务。
但是,如果您想要对分布式状态和锁定进行更多控制,您可以尝试使用分布式数据网格,例如 Hazelcast 和 Gemfire。
我亲自使用过 Hazelcast,它确实提供了锁定地图中条目的方法。
#编辑2
尽管我相信 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
Run Code Online (Sandbox Code Playgroud)
然而,值得庆幸的是 Spring 已经通过RedisLockRegistry提供了这种分布式锁实现。有关使用的更多文档请参见此处。
如果您决定使用不带 spring 的普通 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();
}
Run Code Online (Sandbox Code Playgroud)
这两者的工作方式应该与 Hazelcast 锁定完全相同。