【问题标题】:Two threads reading from the same table:how do i make both thread not to read the same set of data from the TASKS table从同一个表中读取的两个线程:我如何使两个线程不从 TASKS 表中读取同一组数据
【发布时间】:2011-11-15 10:19:22
【问题描述】:

我有一个任务线程在两个独立的 tomcat 实例中运行。 Task 线程在特定 where 条件下同时读取(使用 select)TASKS 表,然后进行一些处理。

问题是,有时两个线程都会选择同一个任务,因此该任务会执行两次。 我的问题是如何让两个线程不从 TASKS 表中读取同一组数据

【问题讨论】:

  • 你必须考虑同步和隔离。
  • 不可能在 JAVA 级别进行同步,因为线程在两个单独的 tomcat 机器中运行。您是指数据库级别...如果是这样,请添加更多详细信息,说明最适合哪种隔离策略以及如何使用 .thankx
  • 您必须将数据库连接上的隔离设置为可序列化。它会花费你一些性能,但你会得到它的正确性。
  • 是的,这是一种选择,但是由于我使用休眠将隔离设置为可序列化,它会影响整个应用程序的性能。有没有办法设置特定于表的隔离策略

标签: java multithreading isolation-level transaction-isolation


【解决方案1】:

只是因为你的代码(正在访问数据库)DAO函数没有同步。让它同步,我想你的问题会解决的。

【讨论】:

  • 不,这不是这里的问题,我已经明确提到线程运行在两个不同的 tomcat 上
【解决方案2】:

如果你提到的TASKS table 是一个数据库表,那么我会使用事务隔离。

作为建议,在事务中,将TASK table 的属性设置为某个唯一可识别的值(如果未设置)。提交牵引。如果一切正常,则该任务已被线程选中。

我还没有遇到过这个用例,所以请谨慎对待我的建议。

【讨论】:

    【解决方案3】:

    我认为您需要了解一些信息如何与任何企业作业调度程序一起工作,例如Quartz

    【讨论】:

      【解决方案4】:

      对于您的用例,有一个更好的工具来完成这项工作——那就是消息传递。您正在持久化需要处理的项目,然后尝试在工作人员之间同步访问。在进行这项工作时,您需要解决许多问题 - 通常更新表并从中选择不应该混合(它锁定),因此在那里存储状态不起作用;您的 Java 代码中的同步也不会,因为服务器重新启动后它不会继续存在。

      将 JMS API 与 ActiveMQ 等消息代理一起使用,您可以将消息发布到队列。该消息将包含要执行的任务的详细信息。消息代理会将其保存在某个地方(在它自己的消息存储或数据库中)。然后,工作线程将订阅消息代理上的队列,并且每条消息只会被传递给其中一个。这是一个非常强大的模型,因为您可以有数百个消息消费者都在执行任务,因此它可以很好地扩展。您还可以根据需要使其具有弹性,因此任务可以在 Tomcat 和代理重新启动时继续存在。

      【讨论】:

        【解决方案5】:

        数据库能否提供优雅的管理很大程度上取决于它是使用严格的两阶段锁定 (S2PL) 还是多版本并发控制 (MVCC) 技术来管理并发。在 MVCC 下读取不会阻塞写入,反之亦然,因此很可能用相对简单的逻辑来管理它。在 S2PL 下,您将花费太多时间阻止数据库成为管理此问题的良好机制,因此您可能希望查看外部机制。当然,无论数据库如何,外部机制都可以工作,但对于 MVCC,它并不是真正必需

        使用 MVCC 的数据库有 PostgreSQL、Oracle、MS SQL Server(在某些配置中)、InnoDB(SERIALIZABLE 隔离级别除外),可能还有许多其他数据库。 (这些是我知道的副手。)

        我没有在问题中找到任何关于您使用的是哪种数据库产品的线索,但如果是 PostgreSQL,您可能需要考虑使用咨询锁。 http://www.postgresql.org/docs/current/interactive/explicit-locking.html#ADVISORY-LOCKS我怀疑很多其他产品都有类似的机制。

        【讨论】:

          【解决方案6】:

          我认为你需要有一些变量(列)来保存行的最后修改日期。您的线程可以读取具有相同修改日期限制的同一组数据。

          编辑: 我没看到“不读书”

          在这种情况下,您需要有另一个表 TaskExecutor (taskId , executorId) ,当某个线程运行任务时,您将数据放入 TaskExecutor;当您启动另一个线程时,它只会检查任务是否已经执行(从 RanTask 中选择 ...,其中 taskId = ...)。 您还需要注意事务的隔离级别。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-04-01
            • 2022-01-05
            • 2010-11-28
            • 2016-06-27
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多