跨群集共享Java同步块,还是使用全局锁?

我有一些代码,我只想允许一个线程访问。 我知道如何使用synchronized块或方法完成此操作,但这是否适用于集群环境?

目标环境是WebSphere 6.0,在集群中有2个节点。

我觉得synchronized不起作用,因为每个节点上的每个应用程序实例都有自己的JVM,对吧?

我在这里尝试做的是在系统启动时对数据库记录执行一些更新。 它将查找比代码版本更旧的任何数据库记录,并执行特定任务以更新它们。 我只希望一个节点执行这些升级,因为我想确保每个工作项只升级一次,并且这些升级的性能不是一个大问题,因为它只发生在应用程序启动时,它只是真正做任何事情自上次启动以来代码更改的时间。

数据库是DB2v9,我通过JNDI直接访问它(没有ORM层)。

有人建议全球锁定可能是这里的方式,但我不知道如何做到这一点。

有没有人在这个舞台上有任何指针?

谢谢!

您是正确的,跨进程的同步将无法使用Java同步构造。 幸运的是,您的问题实际上不是代码同步,而是与数据库同步交互。

处理此问题的正确方法是使用数据库级别锁定。 据推测,您有一些包含db模式版本的表,因此您应确保在启动/升级过程中锁定该表。

如果您指定了数据库类型(DB2?)和访问方法(原始sql,jpa等),那么所涉及的精确sql / db调用可能会更清楚。

更新(2009年8月4日下午2:39) :我建议在一些持有模式版本号的表上使用LOCK TABLE语句。 这将序列化对该表的访问,从而防止两个实例同时运行升级代码。

是的,你是正确的,因为同步块在集群中不起作用。 正如您所说,原因是每个节点都有自己的JVM。

但是,有一些方法可以使同步块在集群中工作,因为它们可以在单节点环境中工作。 最简单的方法是使用像Terracotta这样的产品,它将处理不同JVM之间的线程协调,以便可以在整个集群中使用正常的并发控制。 有很多文章解释了它是如何工作的,比如OpenTerracotta简介 。

当然还有其他解决方案。 这主要取决于你真正希望在这里实现的目标。 如果需要扩展,我不会使用数据库锁进行同步,因为DB不需要。 但我真的恳请你找到一个现成的解决方案,因为乱搞集群同步是混乱的业务:)

您也可以使用像http://www.hazelcast.com/这样的内存数据网格。 这是一种支持锁定的分布式数据结构。

既然你在谈论2台机器,你甚至没有共享内存,所以没有什么可以同步的。

我们用我们的数据库做类似的事情。 这是通过在表中添加记录版本来实现的。 这是你应该做的,

  1. 添加记录/行版本列。
  2. 浏览逻辑以检查记录是否需要更新。
  3. 更新记录时,请确保DB中的记录版本与您拥有的记录版本相同。
  4. 每次写入数据库时​​都会更新版本。

如果遵循这些规则,您应该只有一台服务器更新数据库。

你不能简单地锁定表(或整个数据库)进行更新,所以当获得锁的第一个节点时,所有其他节点都无法写入。 后续节点将等待,并且当释放锁时,代码将被更新,因此不需要记录更新。