正确使用ConcurrentLinkedDeque

时间:2018-08-11 02:52:00

标签: java

您好,而不是使用linkedlist with (reentrant lock)或使用ArrayList (with Collections.synchronizedList),我读到使用ConcurrentLinkedDeque可以消除使用读/写锁的麻烦。我想做的是添加一个游戏角色对象,每次角色进入地图(场)或离开地图时,都会添加和删除该对象。我们一次可以有数百名玩家进入或离开任何地图...

这就是我所做的

private final ConcurrentLinkedDeque<User> charUsers;

public Field() {
    this.charUsers = new ConcurrentLinkedDeque<>();
}

public User getUserByID(int id) {
    return charUsers.stream().filter(c -> c.getId() == id).findFirst().orElse(null);
}

public void addUser(User chr) {
    if (!charUsers.contains(chr)) {
        charUsers.add(chr);
    }
    broadcastPacket(UserPool.userEnterField(chr), chr);
}

public void removeUser(User chr) {
    charUsers.remove(chr); // or charUsers.remove();?
    broadcastPacket(UserPool.userLeaveField(chr), chr);
}

public void broadcastPacket(byte[] outPacket, User exceptChr) {
    charUsers.stream().filter(chr -> !chr.equals(exceptChr)).forEach(
            chr -> chr.getClient().getSession().send(outPacket)
    );
}

我有点担心并发性,并且我已经读到ConcurrentLinkedDeque在多线程环境中是线程安全的,但是在使用迭代器时它的一致性很弱。我正在尝试避免使用任何ConcurrentModificationExceptions

如果不是这种情况,我最好使用sync.List与ArrayListLinkedList一起使用吗?

与该游戏设计有关的一个附带问题,我基于一个相当古老的基于Java的游戏,我相信当时该游戏使用的是Java 1.5,而他们使用hashmaps来添加/删除实体/对象游戏(字符,地图,生物,npc)。我相信即使使用ReentrantLock也存在一些并发问题。所以我正在尝试另一种方法。 (尽管可能有其他因素导致该问题,但我认为这是主要因素)。

1 个答案:

答案 0 :(得分:0)

因此,从您发布的代码来看,看来charUsers所使用的只是跟踪当前地图中的所有内容。您正在浏览集合以查找实体,并正在添加和删除实体。您担心并发访问集合吗?那么一致性,您对此担心吗?就像,线程A添加了一个事物,线程B移除了它,然后线程A尝试采取行动,好像该事物仍在集合中;你关心?这是您的并发问题的一部分。

现在,如果您想要的是 list ,则链表非常有用,并且您将一直在添加和删除节点,而不必在末尾。但是,如果您要在集合中搜索特定项目,而又几乎不关心所有项目,那么链接列表会很糟糕。毕竟,也许您想要一张地图-ConcurrentHashMap,其中键是事物的ID,值是事物。每次搜索事物时,您都必须遍历该列表,直到找到它为止,结果是一个O(N)问题,对了,在遍历该列表时,您会遇到并发修改的风险。 (如果要刻录RAM,则可能需要一个CopyOnWriteArrayList)。

我同意另一位评论者的意见,即这个问题可能范围太广,无法获得可靠的是/否答案。有很多不同的方法可以最大程度地减少同步和并发访问的成本,但是它们都是受系统目标驱动的。一种方法可能对一种系统有用,但对另一种系统却很糟糕。

我建议您做一些幼稚且可行的事情,并对它进行性能分析,或者以其他方式根据您期望的结果衡量其性能。这样可以让您看到真正需要优化的地方。