竞争条件:Kryo 不断尝试使用引用序列化项目

问题描述

我正在使用 KryoNet 使用程序生成的宇宙编写视频游戏。

一些上下文,KryoNet 将序列化对象,然后对象中的每个引用连同它并尝试将其发送到连接的另一端,如果它发现无法序列化的内容,它会抛出一个错误

现在我正在尝试游戏的多人游戏部分,但我遇到了竞争条件的问题,其中一个线程通过将对象添加到带有引用的集合进行修改,例如它添加一个带有引用的对象当我压缩对象并通过网络发送它之间的一个线程,因此它序列化整个对象图,当它收到对象后应该在客户端找到相应的ID时,找到具有我在上面得到的ID的对象服务器,并在到达连接的另一端时重新构建引用。

示例:

public class Fleet()
{
...
List shipList;
...
public void SendToClient()
{
    for (Ship ship : shipList)
    {
    this.DoNotModify = true;
    ship.compress();   //Function that removes all class references from it and assigns an object specific ID
    for (int i=0;i<MultiplayerController.clients.size();i++)
    clients.get(i).connection.sendTCP(object);
    ship.decompress(); //Reassign class references from ID's by looking them up from a HashMap
    this.DoNotModify = false;
    }
}

public void AddShip(Ship ship)
{
    if (!this.DoNotModify)
    {
    ...
    //execute time expensive code
    ...
    shipList.add(ship);
    }
}

}

这是伪代码,但最终发生的事情是在它调用 ship.compress() 和 connection.SendTCP() 之间,它在另一个线程上调用 shipList.add(),该线程添加了一艘船,其中包含对整体的引用行星,并且行星有对其他军队的引用,依此类推,它发送整个对象图。或者它遍历对象图并尝试发送一个不会序列化的对象,但它会因 KryoNetException 而爆炸。

所以我想弄清楚该怎么做,但是因为我无法添加一个标志来检查它是否在两个方法调用之间被修改,在几个玩家进入游戏后不可避免地爆炸了,还没有找到解决方案。可能有一些简单的方法可以修复这种竞争条件,但是使用“同步”关键字在这里不起作用,因为它们是单独的方法调用在这里创建我自己的锁也不起作用,因为它在不同的线程上同时运行这两个函数,并且在检查布尔值后它会运行该函数,尝试删除引用,然后尝试序列化一堆它不应该的东西.

我什至想过创建一种队列,当线程在 Thread.Sleep() 或其他东西上时,它会序列化事物,但这将是我不想创建的整个屁股的痛苦一个完整的子系统。

想法?我在这里不知所措。如果有一个简单的修复,请告诉我,我全神贯注。

解决方法

您可以使 ship.compress 返回一艘新船(如克隆),删除所有引用,并使用它而不是实际的船引用。 这也意味着您不必解压

compressedShip = ship.compress(); // return a clone with removed references

顺便说一下,方法同步适用于同一个对象的多个方法。它用于在 2 个或更多单独的方法调用之间进行同步。 https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...