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

时间:2015-06-28 12:15:50

标签: java lambda parallel-processing

我正在制作游戏,并且有一个 ConcurrentHashMap ,其中包含当前登录的所有玩家。我有一个AutoSaver线程循环通过HashMap并将所有玩家1保存为1。没有多少玩家这很好,因为它不需要花费太多时间来迭代,但是当有很多玩家登录时它可以减慢一点。我使用java流和并行读取,我们可以加快集合的处理,所以我尝试将现有循环更改为现在使用并行

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

这是现有的实施

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

这是我使用流和并行

的实现
ActiveConnections.getAllConnectedPlayers().values()
    .stream()
    .parallel()
    .filter((x) -> x != null)
    .forEach((x) -> saveManager.savePlayer(x, true));

修改 这是我的保存管理器实现

public class SaveManager {

    private MySqlManager sqlManager;

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

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

我再次开始使用lambdas,所以如果出现问题请告诉我。

1 个答案:

答案 0 :(得分:1)

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

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

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

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

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

来自" Java 8 in Action&#34的示​​例书:

public static long parallelSum(long n){
   return Stream.iterate(1L, i -> i + 1) // generate a stream of long values, starting at 1
                .limit(n) // limit the stream to n items
                .parallel()
                .reduce(0L, Long::sum); // this is what we want to execute concurrently, and in the end the result of each sub-stream will be combined using this sum
}

有关详细信息,请参阅本书第7章。