并发 - 循环大数据集并执行操作

时间:2017-10-06 18:18:40

标签: java multithreading concurrency

一些背景

所以我目前正在开发一个游戏项目,我加入了课外活动,并且在过去一年左右的时间里确实意识到了线程问题和并发性的后果。

我们当时遇到的一个重大问题是关闭服务器并保存:断开所有客户端并保存它们被证明是一个问题,因为我们会遇到并发问题。虽然我们已经解决了这个问题,但我又遇到了另一种可能的并发问题。

问题

我目前正在参与游戏的万圣节活动,并且应该每隔一段时间举行一次全球活动,其中所有玩家在该特定时间在线直接收到礼物他们的库存。

通常情况下,我会考虑在线抓住当前的玩家并运行所有玩家并给他们一个项目,但我相信会有这样的后果。

可能出现的问题

  1. 如果玩家在迭代过程中退出,我可能会遇到问题。但是,我们确实用一个线程安全的哈希映射来包装跟踪玩家及其状态的结构。这是否意味着如果我首先执行以给出奖励,如果玩家试图退出,他们将被迫留下,直到给出所有奖励的代码已经完成执行?我并没有完全写入或更改数据结构中的任何内容,因此我担心注销将会通过,并且我试图将项目提供给已经注销的人。
  2. 如果玩家登录,他们将无法进入礼物周期的当前迭代。也许这是一件好事,因为一旦礼品处理已经开始,那些加入的人在技术上已经迟到了。
  3. 我想知道是否有更好的方法来解决这个问题。也许我可以将礼物分发到一个中心位置,玩家可以在这里稍后捡起它,从而避免可能成百上千的玩家的巨大循环。 我们确实遇到了大约200名在线玩家的并发问题

    MVE

    由于我正在讨论迭代大型数据集的概念以及与之相关的并发问题,因此我不太确定要在MVE中提供什么,我不认为非常容易复制(?)。如果我错了,我会尽力提供与代码相关的内容。

1 个答案:

答案 0 :(得分:1)

理想情况下,没有内部技术限制要求用户登录才能收到礼物。但听起来你确实遇到过这样的问题。

弱参考

如果您收集的用户对象是为了在用户退出时赠送礼物成为垃圾收集的候选者,那么您的送礼收藏品应该weak references保留给这些用户对象。弱引用允许垃圾收集继续进行,而常规强引用将取消引用对象成为垃圾收集候选者的资格。见WeakReference class。

创建一个空的ListSet

List< WeakReference< User > > u = new ArrayList< User >() ;

迭代您当前登录的用户。将每个用户对象包裹在WeakReference中。对于送礼,迭代第二个列表/集合,检查每个WeakReference以查看其指示对象是否仍然可用,如果是,则给予礼物。如果没有,请转到下一个。

WeakReference< User > weakUser = new WeakReference<>( user );
u.add( weakUser ) ;

收集后,将该列表包装为不可变的习惯。

List< WeakReference< User > > users = Collections.unmodifiableList( u );

实际上,每当您要求当前登录的用户时,您的用户管理模块应该发出这种不可修改的WeakReference对象列表/集。即使在组装初始列表/集合时,这些用户也可能随时注销。并始终发出一个新实例化的新集合,一个维护在您的用户管理模块内部的集合的副本。因此,如果构建WeakReference的新列表/集合,您的送礼代码不应该执行此工作;应该已经代表它完成了这项工作。

顺便说一下......如果你有多个核心在生产中,并且想要得到想象,你可以将你的WeakReference对象集合提供给新的Java 8 Streams功能,自动拆分为并行处理你的送礼。

提示:您似乎太担心性能,并不担心并发性。

  • 创建包含在WeakReference中的元素集合非常快,而不是问题。在内存中分配引用几乎没有时间。
  • 相比之下,无论负载如何,并发性总是是一个问题,与您对200个用户的评论相矛盾。 即使是单个用户也可能会在送礼期间巧合地注销。程序员通常很难掌握罕见事件一直发生的讽刺意味!更糟糕的是,在生产环境中,添加Murphy's Law。并发性是苛刻的,反复无常的,任意的。

提示:通过Java Concurrency In Practice,Oracle的 Java语言架构师阅读并重读本书Brian Goetz。我第五次重读。