2015-06-28 11 views
5

Tworzę grę i mam ConcurrentHashMap, która zawiera wszystkich graczy, którzy są obecnie zalogowani. Mam wątek AutoSaver, który wykonuje pętlę przez HashMap i zapisuje wszyscy gracze 1 przez 1. Jeśli nie ma wielu graczy, to jest w porządku, ponieważ nie zajmuje to zbyt wiele czasu, ale może nieco zwolnić, gdy zaloguje się wielu graczy. Czytam przy użyciu strumienia java i równolegle, możemy przyspieszyć przetwarzanie zbiorów, więc próbowałem zmienić istniejącą pętlę, aby teraz używać stream i równolegle.Zmiana istniejącej pętli foreach na ConcurrentHashMap w celu użycia Lambdas do wykorzystania przetwarzania równoległego

Moje pytanie brzmi, czy moja implementacja jest poprawna? Czy istnieje lepszy sposób na zrobienie tego? Czy teraz wątek jest bezpieczny?

Oto istniejące wdrożenie

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

Tu jest moja realizacja przy użyciu strumienia i równolegle

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

EDIT Oto mój Zapisz realizacji menedżera

public class SaveManager { 

    private MySqlManager sqlManager; 

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

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

zysk Właśnie zacząłem używać lambdas, więc daj mi znać, jeśli coś jest nie tak.

+0

To mi odpowiada ... To pytanie może być lepiej dostosowane do [Przeglądu kodu] (http://codereview.stackexchange.com/). –

+0

Nie miałem pojęcia, że ​​istnieje jak przegląd kodu na przepełnieniu stosu. :) Przeniesię go, jeśli będzie to wymagane. – Sneh

+0

Dokumentacja "ConcurrentHashMap" jasno stwierdza, że ​​"[...] Podobnie jak Hashtable, ale w przeciwieństwie do HashMap, ta klasa nie pozwala na użycie wartości null jako klucza lub wartości." - dlaczego więc test na zero? – fge

Odpowiedz

1

Jest bezpieczny dla wątków, jeśli savePlayer jest zapisem wątku. Przekierowanie strumienia na równoległy nie powoduje, że wątek jest bezpieczny, czyni algorytm zdolnym do zrównoleglania.

Jeśli jednak twój savePlayer zapisuje dane w bazie danych, nie ma możliwości zrównoleglenia części składowej odtwarzacza, która jest tym, czego potrzebujesz. Co oznacza, że ​​zobaczysz żadnych korzyści z używania równoległy strumień bo gdy jeden wątek zmienia zawartość DB, dwie rzeczy mogą się zdarzyć:

  • drugi wątek, który chce uratować innego gracza, czeka na pierwszą gwint do wykończenia. W takim przypadku nie ma korzyści z korzystania z równoległych strumieni, ponieważ wątki wciąż muszą czekać na siebie nawzajem.

  • Drugi wątek próbuje zmienić dane bazy danych w tym samym czasie ma pierwszy wątek, który może prowadzić do niespójnych danych w bazie danych. Zakładając, że twój kod obsługuje więcej niż jedno aktywne połączenie z bazą danych.

Podsumowując, należy użyć strumienia równoległego, gdy algorytm, który chcesz wykonać, można zsynchronizować. Wewnętrznie, parallelStream() dzieli strumień na podstrumienie i wykonuje algorytm dla każdego elementu w każdym z podstrumieni (jednocześnie), na końcu wynik każdego pod-strumienia jest łączony przy użyciu tego samego algorytmu.

Przykładem od „Java 8 w działaniu” książki:

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 
} 

Więcej informacji znajduje się w rozdziale 7 książki.

+0

Edytowałem moje pytanie i dodałem klasę SaveManager. Nie jestem pewien, w jaki sposób mogę skończyć ze spójnymi danymi w bazie danych. – Sneh

+1

Jesteś odbiegający od punktu. Chodzi o to, że jeśli savePlayer jest bezpieczny dla wątków, to twój kod lambda jest poprawny i wątek bezpieczny. Zapewnienie spójności danych można zapewnić za pomocą transakcji atomowych, wykorzystując mechanizmy zatwierdzania i wycofywania. Niespójność danych stanowi problem, jeśli główny wątek może zmieniać dane gracza w tym samym czasie, w którym wątek AutoSave zapisuje graczy. Ale nie wiem, czy to się może zdarzyć, więc założyłem, że to możliwe. – pedromss

+0

Tak, to może się zdarzyć. Mój główny wątek może zmienić wartość gracza, powiedzmy jego pozycję na mapie gry (jeśli gracz się porusza). Więc myślę, że rozumiem. Dzięki – Sneh

Powiązane problemy