我有一个多线程Java程序,每个线程获得一个用户名进行某些处理,大约需要10分钟左右。
现在它通过sql查询获取用户名,该查询随机返回一个用户名,问题是一次可以为多个线程提供相同的用户名。
我不希望线程正在处理的用户名被另一个线程再次获取。实现这一目标的简单方法是什么?
答案 0 :(得分:1)
分步解决方案:
创建一个用于存储线程状态的线程表。在其他列中,您还需要存储所有者用户的ID。
当线程与用户关联时,创建一条记录,存储所有者以及所有其他多汁的东西。
当线程不再与用户关联时,请将其所有者设置为null。
线程完成作业后,删除其记录。
当您将用户随机化为线程时,过滤掉至少已与某个线程关联的所有用户。通过这种方式,您可以了解随机化结束时的任何用户都是无线的。
确保一切就绪。如果在处理该功能时,某些线程记录已创建并应从其所有者处删除或处理,则执行此操作。
答案 1 :(得分:0)
有很多方法可以做到这一点......我可以想到这个问题的三个解决方案:
1)包含数组的单例类,其中包含已在使用的所有用户。确保同步对阵列的访问,并从中删除未使用的用户。
2)用户表中的一个标志,其中包含引用正在使用它的线程的唯一标识。从表中删除标志后必须进行管理。
- >作为替代方案,为什么要检查所有线程共享的连接池是否可以解决您的问题?
答案 2 :(得分:0)
你可以做一个batch query,它从数据库中返回你想要的所有用户名,并将它们存储在List(或某种类型的集合)中。
然后确保对此列表的同步访问,以防止两个线程同时使用相同的用户名。使用同步列表或同步方法访问列表并从列表中删除用户名。
答案 3 :(得分:0)
一种方法是在users表中添加另一列。此列是一个简单的标志,显示用户是否有指定的线程。
但是当您查询数据库时,您必须将其包装在事务中。 您开始事务,然后首先选择一个没有线程的用户,之后您更新标志列,然后提交或回滚。 由于查询包含在事务中,因此db处理在这种情况下发生的所有问题。
使用此解决方案,您无需在代码中实现同步机制,因为数据库将为您执行此操作。
如果您在执行此操作后仍有问题,我认为您必须配置数据库服务器的隔离级别。
答案 4 :(得分:0)
您似乎想要一个工作队列系统。不要重新发明轮子 - 使用完善的现有工作队列。
对于关系数据库来说,健壮,可靠的并发工作排队是不幸的。大多数"解决方案"登陆:
由于工人重启或崩溃而无法应付未完成的工作项目;
实际上是把锁上的所有工作序列化,所以除了一个工人外只有等待;和/或
允许多次处理工作项
PostgreSQL 9.5的新FOR UPDATE SKIP LOCKED
功能可以让您更轻松地在数据库中执行您想要的操作。目前,使用预制的可靠任务/工作/消息队列引擎。
如果您必须自己执行此操作,那么您将需要一个活动工作项表,您可以在其中记录处理行的工作人员的活动进程ID /线程ID。您将需要一个定期运行,线程崩溃和程序启动时运行的清理过程,该过程将删除失败作业的条目(工作进程不再存在),以便重新尝试它们。
请注意,除非工作人员所做的工作是在将工作队列项标记为已完成的同一事务中提交给数据库的,否则您将遇到可以完成工作的时间问题,然后它的数据库条目就不会出现。标记为已完成,导致重复工作。绝对要防止这种情况要求您在与标记工作完成的更改相同的事务中将工作提交到数据库,或者使用两阶段提交和外部事务管理器。