Java 更改ConcurrentHashMap上现有的foreach循环以使用Lambdas来利用并行处理

Java 更改ConcurrentHashMap上现有的foreach循环以使用Lambdas来利用并行处理,java,lambda,parallel-processing,Java,Lambda,Parallel Processing,我正在制作一个游戏,有一个ConcurrentHashMap,其中包含当前登录的所有玩家。我有一个自动保存线程,它在HashMap中循环并逐个保存所有播放器。当玩家不多时,这很好,因为迭代不会花费太多时间,但当有很多玩家登录时,它会稍微慢一点。我阅读了java stream和parallel,我们可以加快集合的处理,所以我尝试将现有循环更改为现在使用stream和parallel 我的问题是,我的实现正确吗?有更好的方法吗?现在线程安全吗 下面是现有的实现 for(Player player :

我正在制作一个游戏,有一个ConcurrentHashMap,其中包含当前登录的所有玩家。我有一个自动保存线程,它在HashMap中循环并逐个保存所有播放器。当玩家不多时,这很好,因为迭代不会花费太多时间,但当有很多玩家登录时,它会稍微慢一点。我阅读了java stream和parallel,我们可以加快集合的处理,所以我尝试将现有循环更改为现在使用streamparallel

我的问题是,我的实现正确吗?有更好的方法吗?现在线程安全吗

下面是现有的实现

for(Player player : ActiveConnections.getAllConnectedPlayers().values(){
    if(player != null)
        saveManager.savePlayer(player, true);
}
public class SaveManager {

    private MySqlManager sqlManager;

    public SaveManager(){
        sqlManager = MySqlManager.getInstance();
    }

    public void savePlayer(Player player, boolean autoSave){
       //Saves the player
    }
下面是我使用流和并行的实现

ActiveConnections.getAllConnectedPlayers().values()
    .stream()
    .parallel()
    .filter((x) -> x != null)
    .forEach((x) -> saveManager.savePlayer(x, true));
编辑 这是我的存储管理器实现

for(Player player : ActiveConnections.getAllConnectedPlayers().values(){
    if(player != null)
        saveManager.savePlayer(player, true);
}
public class SaveManager {

    private MySqlManager sqlManager;

    public SaveManager(){
        sqlManager = MySqlManager.getInstance();
    }

    public void savePlayer(Player player, boolean autoSave){
       //Saves the player
    }

同样,我刚刚开始使用lambdas,所以如果有什么问题,请告诉我。

如果savePlayer是线程保存,则是线程安全的。将流转换为并行流并不能使其线程安全,而是使算法能够并行化

但是,如果您的savePlayer将内容保存在数据库中,则无法并行化您想要的播放器保存部分。这意味着您将看不到使用并行流的好处,因为当一个线程更改DB的内容时,可能会发生两种情况:

  • 想要保存另一个玩家的第二个线程等待第一个线程完成。如果是这种情况,那么使用并行流没有任何好处,因为线程仍然必须等待彼此

  • 第二个线程试图在第一个线程的同时更改数据库数据,这可能会导致数据库中的数据不一致。假设您的代码支持多个到数据库的活动连接

总之,当要执行的算法可并行化时,应该使用并行流。在内部,parallelStream()将流划分为子流,并对每个子流上的每个项目执行算法(并发),最后使用相同的算法组合每个子流的结果

“Java 8正在运行”一书中的一个示例:


有关更多信息,请参阅本书的第7章。

我觉得这很合适。。。不过,这个问题可能更适合。我不知道在堆栈溢出问题上会有类似代码检查的问题。:)如果需要,我将移动它。
ConcurrentHashMap
的文档明确指出“[…]与Hashtable类似,但与HashMap不同,此类不允许将null用作键或值。”--那么为什么要测试null?你是对的,不需要null检查。我会移除它。从来没有读过@FGE什么是savePlayer实现?我已经编辑了我的问题并添加了SaveManager类。我不知道如何才能在数据库中得到一致的数据。你偏离了重点。关键是,如果savePlayer是线程安全的,那么lambda代码是正确的,也是线程安全的。使用提交和回滚机制,可以通过原子事务确保数据库数据的一致性。如果主线程可以在自动保存线程保存播放机的同时更改播放机数据,则数据不一致是一个问题。但是我不知道这是否会发生,所以我认为这是可能的。是的,这是可能发生的。我的主线程可以改变玩家的值,比如说他在游戏地图上的位置(如果玩家正在移动)。所以我想我明白你的意思了。谢谢