如何获得对某些会话条目的独占访问权限?

Meh*_*ran 7 java session locking spring-session

由于REST服务的远程调用特性,它们处于不断变为竞争状态的状态.比赛的日常资源之一是会议.为了实用,您需要能够在流程开始时锁定资源,并在完成任务后将其提升.

现在我的问题是,Spring Session是否有任何功能来处理会话条目中的竞争条件?

或者Java中的任何其他库/框架!

11t*_*ion 3

如果您使用 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. 休息的工作方式与单个会话相同,存在单个容器,因此锁定会话就足够了。

如果您想跨实例使用会话共享, TomcatJetty等容器提供支持

这些方法使用后端数据库或其他一些持久性机制来存储状态。

出于同样的目的,您可以尝试使用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 锁定完全相同。