我有一个java应用程序,其中15个线程通过名为getNext()的同步方法从表中选择一行11,000条记录,线程在选择一行时变慢,从而花费了大量时间。每个线程都遵循以下过程:
线程检查是否存在恢复列值设置为1的行。
一个。如果存在,则线程获取该行的id并使用该id选择id大于获取id的另一行。
B中。否则,它选择id大于0的行。
根据上述1中描述的步骤结果收到的最后一行标记为恢复列设置为1.
线程获取行数据并对其进行处理。
问题:
答案 0 :(得分:1)
1 .: 似乎getNext()艺术中的多个数据库操作是瓶颈。如果数据没有被外部源更改,您可以读取所有行的“id”和“resume”并缓存它。比你只有一个查询而不是只在内存中进行读取操作。这将在getNext()中安全地进行大量昂贵的DB调用:
2 .: 基本上,您需要某种事务,或者至少添加一个在线程完成处理该行时更新的其他列。基本上,处理和更新需要在单个事务中发生。当事务未完成时发生某些事情时,您可以回滚到未处理该行的状态。
答案 1 :(得分:1)
如果线程都在同一台机器上,那么它们可以使用共享数据结构来避免处理相同的事情而不是同步。但以下假设线程在不同的机器上(可能是应用程序服务器集群的不同成员),并且只能通过数据库进行通信。
删除getNext()方法上的同步。将恢复标志设置为1(步骤2)时,请以原子方式执行此操作。 update table set resume = 1其中resume = 0,commit。只有一个线程会成功,这个线程确实得到了这个工作单元。同时,设置一个恢复时间 - 如果恢复时间大于某个最大值假设处理该工作单元的线程哈希崩溃,则将resume标志恢复为0.工作完成后,将恢复时间设置为null ,或以其他方式将工作标记为已完成。
答案 2 :(得分:1)
嗯,这里会想到不同的问题:
您是否在数据库中保留状态?我会寻找一种方法,你可以调用select for update,你可以按非活动状态过滤(确保只在select中获取一行)并立即更新为active(在同一个事务中)。很高兴知道你正在使用什么数据库,不确定“选择更新”是否总是一个选项。
处理完成后,请更新为已完成状态。
请务必在表格中保留时间戳,以便在最后一次更改状态时进行识别。让自己成为决定何时将活动线程视为丢失的规则。
定义其他可能的错误情况(如果进程失败会发生什么情况)。
您还需要分析方案。你的桌子有多少行?有多少线程同时调用它?在给定时间内发生了多少次插入?根据这一点,您将看到DB性能如何运行。
我假设你的getNext()是同步的,我在第1点写的你可能会解决这个问题......