Útmutató a ConcurrentSkipListMap-hoz

1. Áttekintés

Ebben a gyors cikkben megnézzük a ConcurrentSkipListMap osztály a java.util.egyidejű csomag.

Ez a konstrukció lehetővé teszi számunkra, hogy zár nélküli módon hozzon létre szálbiztos logikát. Ideális azokra a problémákra, amikor megváltoztathatatlan pillanatképet akarunk készíteni az adatokról, miközben más szálak még mindig beillesztik az adatokat a térképbe.

Meg fogjuk oldani a problémát rendez egy eseményfolyamot, és pillanatképet készít az elmúlt 60 másodpercben érkezett eseményekről az adott konstrukció segítségével.

2. Adatfolyam rendezési logika

Tegyük fel, hogy van egy eseménysorunk, amely folyamatosan több szálból származik. Képesnek kell lennünk az elmúlt 60 másodperc eseményeinek és a 60 másodpercnél régebbi események felvételére is.

Először határozzuk meg eseményadataink felépítését:

public class Esemény {private ZonedDateTime eventTime; privát String tartalom; // szabványos kivitelezők / szerelők}

Eseményeinket a eventTime terület. Ennek eléréséhez a ConcurrentSkipListMap, át kell adnunk a Összehasonlító konstruktorának, miközben létrehoz egy példányt:

ConcurrentSkipListMap események = új ConcurrentSkipListMap (Comparator.comparingLong (v -> v.toInstant (). ToEpochMilli ()));

Összehasonlítjuk az összes érkezett eseményt az időbélyegzőjükkel. A Longing () összehasonlítása módszer és a kivonat függvény átadása, amelyre a hosszú időbélyeg a ZonedDateTime.

Amikor megérkeznek eseményeink, csak hozzá kell adnunk őket a térképhez a put () módszer. Vegye figyelembe, hogy ez a módszer nem igényel kifejezett szinkronizálást:

public void acceptEvent (Event event) {events.put (event.getEventTime (), event.getContent ()); }

A ConcurrentSkipListMap kezeli az alatta lévő események rendezését a Összehasonlító amit a konstruktorban adtak át neki.

A ConcurrentSkipListMap azok a módszerek, amelyek zárolás nélküli módon megváltoztathatatlan pillanatfelvételt készíthetnek az adatairól. Az elmúlt percen belül érkező összes esemény megszerzéséhez használhatjuk a tailMap () módszert és tedd el azt az időt, amelyből elemeket szeretnénk kapni:

public ConcurrentNavigableMap getEventsFromLastMinute () {return events.tailMap (ZonedDateTime.now (). mínuszMinutes (1)); } 

Visszaadja az elmúlt perc összes eseményét. Változhatatlan pillanatkép lesz, és ami a legfontosabb, hogy más író szálak új eseményeket adhatnak a ConcurrentSkipListMap külön zárolás nélkül.

Mostantól megkaphatjuk az összes eseményt, amely egy perc múlva később érkezett - a headMap () módszer:

public ConcurrentNavigableMap getEventsOlderThatOneMinute () {return events.headMap (ZonedDateTime.now (). mínuszMinutes (1)); }

Ez az összes, egy percnél régebbi esemény megváltoztathatatlan pillanatképét adja vissza. A fenti módszerek mindegyike a EventWindowSort osztály, amelyet a következő szakaszban fogunk használni.

3. A Sorting Stream Logic tesztelése

Miután végrehajtottuk rendezési logikánkat a ConcurrentSkipListMap, most megtehetjük tesztelje két író szál létrehozásával amely egyenként száz eseményt küld:

ExecutorService végrehajtóService = Executors.newFixedThreadPool (3); EventWindowSort eventWindowSort = new EventWindowSort (); int számOfThreads = 2; Futható producer = () -> IntStream .rangeClosed (0, 100) .forEach (index -> eventWindowSort.acceptEvent (új esemény (ZonedDateTime.now (). MínuszSeconds (index), UUID.randomUUID (). ToString ())) ); for (int i = 0; i <numberOfThreads; i ++) {végrehajtóSzolgáltatás.execute (producer); } 

Minden szál a acceptEvent () módszer, az események elküldése eventTime mostantól a "most mínusz száz másodpercig" értékig.

Közben meghívhatjuk a getEventsFromLastMinute () módszer, amely visszaadja az egy perces ablakon belüli események pillanatképét:

ConcurrentNavigableMap eventsFromLastMinute = eventWindowSort.getEventsFromLastMinute ();

Az események száma a eventsFromLastMinute változik az egyes próbaüzemekben, attól függően, hogy milyen sebességgel küldik el a gyártó szálai az eseményeket a EventWindowSort. Azt állíthatjuk, hogy a visszaküldött pillanatképben egyetlen egy percnél nem régebbi esemény van:

hosszú eseményekOlderThanOneMinute = eventsFromLastMinute .entrySet () .stream () .filter (e -> e.getKey (). isBefore (ZonedDateTime.now (). mínuszMinutes (1))) .szám (); assertEquals (eventsOlderThanOneMinute, 0);

És hogy a pillanatképben több mint nulla esemény található, amelyek egy percen belül vannak:

long eventYoungerThanOneMinute = eventsFromLastMinute .entrySet () .stream () .filter (e -> e.getKey (). isAfter (ZonedDateTime.now (). mínuszMinutes (1))) .szám (); assertTrue (eventYoungerThanOneMinute> 0);

A mi getEventsFromLastMinute () használja a tailMap () alul.

Teszteljük most a getEventsOlderThatOneMinute () hogy használja a headMap () módszer a ConcurrentSkipListMap:

ConcurrentNavigableMap eventsFromLastMinute = eventWindowSort.getEventsOlderThatOneMinute ();

Ezúttal pillanatfelvételt készítünk egy percnél régebbi eseményekről. Azt állíthatjuk, hogy több mint nulla ilyen esemény van:

hosszú eseményekOlderThanOneMinute = eventsFromLastMinute .entrySet () .stream () .filter (e -> e.getKey (). isBefore (ZonedDateTime.now (). mínuszMinutes (1))) .szám (); assertTrue (eventsOlderThanOneMinute> 0);

És ezután nincs egyetlen esemény sem az utolsó pillanatban:

long eventYoungerThanOneMinute = eventsFromLastMinute .entrySet () .stream () .filter (e -> e.getKey (). isAfter (ZonedDateTime.now (). mínuszMinutes (1))) .szám (); assertEquals (eventYoungerThanOneMinute, 0);

A legfontosabb megjegyezni, hogy elkészíthetjük az adatok pillanatképét, miközben más szálak még mindig új értékeket adnak hozzá hoz ConcurrentSkipListMap.

4. Következtetés

Ebben a gyors bemutatóban áttekintettük a ConcurrentSkipListMap, néhány gyakorlati példával együtt.

Kihasználtuk a ConcurrentSkipListMap olyan nem blokkoló algoritmus megvalósítása, amely változatlan pillanatképeket szolgálhat számunkra akkor is, ha egyszerre több szál frissíti a térképet.

Mindezen példák és kódrészletek megvalósítása megtalálható a GitHub projektben; ez egy Maven projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.