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

2022-09-03 02:04:20

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

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

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

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

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

有人建议,全局锁定可能是要走这条路,但我不确定该怎么做。

在这个领域,有人有任何指点吗?

谢谢!


答案 1

是的,你是对的,因为同步块不会在集群中工作。原因在于,正如你所说,每个节点都有自己的 JVM。

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

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


答案 2

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

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

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

更新(8/4/2009 2:39PM):我建议在某个包含架构版本号的表上使用 LOCK TABLE 语句。这将序列化对该表的访问,防止两个实例同时运行升级代码。


推荐