在集群环境中部署的Spring Web App中,Java Concurrent Lock失败

时间:2014-02-03 20:57:16

标签: java multithreading spring cluster-computing

在我的春季网络应用程序中,我有一个服务方法,其中包含一个由锁保护的代码块。 一次只有一个线程可以进入代码块。 这在非群集环境中工作正常,但在群集环境中失败。在集群环境中,在节点内,同步发生但在不同节点之间,代码块并行执行。这是因为在每个节点中都创建了一个单独的Lock对象吗? 有人可以建议我吗?

代码示例

//Service Class
@Service
class MyServiceClass {

private final Lock globalLock;

@Autowired
public MyServiceClass(@Qualifier("globalLock") final Lock globalLock){
    this.globalLock = globalLock;
}

public void myServiceMethod(){
    ...
    globalLock.lock();
    try {
        ...
    }
    finally {
        globalLock.unlock();
    }
    ...

}

}//End of MyServiceClass


//Spring Configuration XML
<bean id="globalLock" class="java.util.concurrent.locks.ReentrantLock" scope="singleton" />

2 个答案:

答案 0 :(得分:0)

如果要在群集环境中同步对象,这意味着涉及许多VM,您的解决方案将涉及所涉及的不同VM之间的某种通信。

在这种情况下,需要一些想象才能完成任务:您需要在所涉及的所有虚拟机共有的某个对象上实现互斥,并且当您将其他计算机放入集群时可能会升级。你有没有想过基于JNDI的解决方案?在这里你有一些东西,但我担心它看起来像是一个学术讨论:

http://jsr166-concurrency.10961.n7.nabble.com/Lock-implementation-td2180.html

总有机会基于数据库机制实现某些功能(始终认为您的数据库是群集中所有节点的核心和公共资源)。您可以根据数据库中实现的某些SELECT FOR UPDATE机制设计一些内容,而不是仅用于同步的一些表...

你有一个有趣的问题!祝你好运

答案 1 :(得分:0)

你是对的,原因是每个节点都拥有自己的锁。要解决此问题,请考虑在数据库中引入一个表SERVICE_LOCKS,其中包含列服务类名称,服务ID,锁定状态和采集时间戳。

对于服务ID,使每个服务使用UUID.randomUUID()生成唯一的分布式ID。

要获取锁定,请发出更新以尝试抓取它,然后查询它以查看是否有锁定。但是不要做选择,检查然后更新。超过一定时间的锁不应该被考虑在内。

这是coarse grained lock design pattern的实现,其中获取应用程序级别的悲观锁定以锁定共享资源。

根据服务的业务逻辑和您使用的事务管理器的类型,将服务方法的隔离级别提高到REPEATABLE_READ可能是一种选择。

对于不涉及数据库的解决方案,请查看基于Actor并发模型的分布式并发处理框架 - The Akka Framework(单击“远程处理”按钮)。