Bevezetés a Java terjesztőjébe

1. Áttekintés

A Elosztó a Java 8-ban bevezetett felület lehet szekvenciák bejárására és particionálására használják. Ez egy alapvető segédprogram Patakok, főleg párhuzamosak.

Ebben a cikkben kitérünk a használatára, jellemzőire, módszereire és a saját egyedi megvalósítások létrehozásának módjára.

2. Elosztó API

2.1. tryAdvance

Ez a fő módszer a szekvenciák átjutására. A módszer, a metódus vesz egy Fogyasztó hogy használják a Elosztó egyenként egymás után és visszatér hamis ha nincsenek olyan elemek, amelyeket be kell járni.

Itt megnézzük, hogyan lehet használni az elemek áthaladásához és particionálásához.

Először tegyük fel, hogy van egy Tömb lista 35000 cikkel és azzal Cikk osztály:

public class cikk {private List listOfAuthors; private int id; privát karakterlánc neve; // szabványos kivitelezők / szerelők / beállítók}

Most hajtsunk végre egy feladatot, amely feldolgozza a cikkek listáját, és kiegészíti a- kiadta Baeldung ” az egyes cikkek nevéhez:

nyilvános karakterlánc-hívás () {int current = 0; while (spliterator.tryAdvance (a -> a.setName (article.getName () .concat ("- Baeldung által kiadott"))))) {current ++; } return Thread.currentThread (). getName () + ":" + current; }

Vegye figyelembe, hogy ez a feladat kiadja a feldolgozott cikkek számát, amikor befejezi a végrehajtást.

Egy másik kulcskérdés, hogy mi használtuk tryAdvance () módszer a következő elem feldolgozásához.

2.2. trySplit

Ezután váljunk szét Elosztók (innen a név) és önállóan dolgozza fel a partíciókat.

A trySplit módszer megpróbálja két részre osztani. Ezután a hívó folyamat elemei, végül a visszaküldött példány feldolgozza a többit, lehetővé téve a kettő párhuzamos feldolgozását.

Először állítsuk elő a listánkat:

public static List geneElements () {return Stream.generate (() -> new Article ("Java")) .limit (35000) .collect (Collectors.toList ()); }

Ezután megkapjuk a Elosztó például a elosztó () módszer. Akkor alkalmazzuk a mi trySplit () módszer:

@Test public void givenSpliterator_whenAppliedToAListOfArticle_thenSplittedInHalf () {Spliterator split1 = Executor.generateElements (). Spliterator (); Splitterator split2 = split1.trySplit (); assertThat (new Task (split1) .call ()) .containsSequence (Executor.generateElements (). size () / 2 + ""); assertThat (new Task (split2) .call ()) .containsSequence (Executor.generateElements (). size () / 2 + ""); }

A felosztási folyamat rendeltetésszerűen működött, és egyenlően osztotta fel a rekordokat.

2.3. becsült méret

A becsült méret A módszer becsült elemszámot ad meg:

LOG.info ("Méret:" + split1.estimateSize ());

Ez eredményezi:

Méret: 17500

2.4. hasCharacteristics

Ez az API ellenőrzi, hogy a megadott jellemzők megegyeznek-e a Elosztó. Majd ha a fenti módszert hívjuk meg, akkor a kimenet egy int ezen jellemzők ábrázolása:

LOG.info ("Jellemzők:" + split1.jellemzők ());
Jellemzők: 16464

3. Elosztó Jellemzők

Nyolc különböző tulajdonsággal rendelkezik, amelyek leírják viselkedését. Ezek felhasználhatók tippekként a külső eszközökhöz:

  • MÉRETES ha képes pontos számú elem visszaküldésére az becslésméret () módszer
  • VÁLOGATOTT - ha válogatott forráson keresztül iterál
  • SUBSIZED - ha felosztjuk a példányt a használatával trySplit () módszerrel, és szerezzen be osztókat, amelyek MÉRETES is
  • EGYIDEJŰ - ha a forrás egyidejűleg biztonságosan módosítható
  • KÜLÖNBÖZŐ - ha minden találkozott elempárra x, y,! x. egyenlő (y)
  • VÁLTOZHATATLAN - ha a forrás birtokában lévő elemek strukturálisan nem módosíthatók
  • NINNULL - ha a forrás nullákat tartalmaz, vagy sem
  • MEGRENDELT - ha egy sorrendben ismétlődik

4. Egy egyedi Elosztó

4.1. Mikor kell testreszabni

Először tegyük fel a következő forgatókönyvet:

Van egy cikkosztályunk a szerzők listájával és azzal a cikkel, amelynek több szerzője is lehet. Ezenkívül figyelembe vesszük a cikkhez kapcsolódó szerzőt, ha a kapcsolódó cikk azonosítója megegyezik a cikk azonosítójával.

A mi Szerző osztály így fog kinézni:

public class Szerző {private String name; private int relatedArticleId; // szabványos mérőeszközök, beállítók és kivitelezők}

Ezután megvalósítunk egy osztályt a szerzők számlálásához, miközben bejárjuk a szerzőket. Azután az osztály redukciót hajt végre a patakon.

Vessünk egy pillantást az osztály megvalósítására:

public class RelatedAuthorCounter {private int counter; privát boolean isRelated; // standard konstruktorok / getterek public RelatedAuthorCounter felhalmozódnak (a szerző szerzője) {if (author.getRelatedArticleId () == 0) {return isRelated? ez: új RelatedAuthorCounter (számláló, igaz); } else {return isRelated? új RelatedAuthorCounter (számláló + 1, hamis): ez; }} public RelatedAuthorCounter kombájn (RelatedAuthorCounter RelatedAuthorCounter) {return new RelatedAuthorCounter (számláló + RelatedAuthorCounter.counter, RelatedAuthorCounter.isRelated); }}

A fenti osztály minden módszere egy meghatározott műveletet hajt végre, amely az utazás során számolásra kerül.

Először is a felhalmozni () módszer végigjárja a szerzőket iteratív módon, azután kombájn() összegez két számlálót az értékeik felhasználásával. Végül a getCounter () visszaadja a számlálót.

Most, hogy teszteljem, mit tettünk eddig. Konvertáljuk cikkünk szerzői listáját a szerzők folyamává:

Stream stream = Article.getListOfAuthors (). Stream ();

És hajtsa végre a countAuthor () módszer az adatfolyam redukciójának végrehajtására a RelatedAuthorCounter:

private int countAutors (Stream stream) {RelatedAuthorCounter wordCounter = stream.reduce (új RelatedAuthorCounter (0, true), RelatedAuthorCounter :: felhalmozódik, RelatedAuthorCounter :: kombinál); return wordCounter.getCounter (); }

Ha szekvenciális folyamot használtunk, akkor a kimenet a vártnak felel meg „Count = 9”azonban a probléma akkor merül fel, amikor megpróbáljuk párhuzamosítani a műveletet.

Vessünk egy pillantást a következő tesztesetre:

@Test void givenAStreamOfAuthors_whenProcessedInParallel_countProducesWrongOutput () {assertThat (Executor.countAutors (stream.parallel ())). IsGreaterThan (9); }

Nyilvánvalóan valami nem stimmelt - az adatfolyam véletlenszerű helyzetben történő felosztása kétszer megszámolta a szerzőt.

4.2. Testreszabás

Ennek megoldásához meg kell megvalósítani a Elosztó ez csak akkor osztja meg a szerzőket, ha rokonok id és articleId mérkőzések. Íme a szokásunk megvalósítása Elosztó:

public class RelatedAuthorSpliterator végrehajtja a Spliterator {private final List list; AtomicInteger current = új AtomicInteger (); // standard konstruktor / getters @Override public boolean tryAdvance (Consumer action) {action.accept (list.get (current.getAndIncrement ())); return current.get () <list.size (); } @Orride public Spliterator trySplit () {int currentSize = list.size () - current.get (); if (currentSize <10) {return null; } for (int splitPos = currentSize / 2 + current.intValue (); splitPos <list.size (); splitPos ++) {if (list.get (splitPos) .getRelatedArticleId () == 0) {Spliterator spliterator = new RelatedAuthorSpliterator ( list.subList (current.get (), splitPos)); current.set (splitPos); visszatérő elosztó; }} return null; } @A nyilvános hosszú becslés felülbírálásaMéret () {return list.size () - current.get (); } @Orride public int features () {return CONCURRENT; }}

Most jelentkezik countAuthors () módszer a helyes kimenetet adja. A következő kód igazolja, hogy:

@Test public void givenAStreamOfAuthors_whenProcessedInParallel_countProducesRightOutput () {Stream stream2 = StreamSupport.stream (spliterator, true); assertThat (Executor.countAutors (stream2.parallel ())). isEqualTo (9); }

Továbbá a szokás Elosztó a szerzők listájából jön létre, és az aktuális pozíció megtartásával halad keresztül rajta.

Beszéljünk részletesebben az egyes módszerek megvalósításáról:

  • tryAdvance átadja a szerzőket a Fogyasztó az aktuális indexpozíción, és növeli annak pozícióját
  • trySplit meghatározza a hasítási mechanizmust, esetünkben a RelatedAuthorSpliterator akkor jön létre, amikor az azonosítók megegyeznek, és a felosztás két részre osztja a listát
  • becsült méret - a különbség a lista mérete és a jelenleg iterált szerző helyzete között
  • jellemzők- adja vissza a Elosztó jellemzők, esetünkben MÉRETES mint a becsült méret () a módszer pontos; ráadásul, EGYIDEJŰ jelzi, hogy ennek forrása Elosztó más szálak biztonságosan módosíthatják

5. A primitív értékek támogatása

A ElosztóAPI támogatja a primitív értékeket, beleértve kettős, int és hosszú.

Az egyetlen különbség egy általános és egy primitív dedikálás használata között Elosztó az adott Fogyasztó és a Elosztó.

Például, amikor szükségünk van rá egy int értéket kell átadnunk egy intFogyasztó. Továbbá, itt van egy lista a primitív dedikáltakról Elosztók:

  • OfPrimitive: szülői felület más primitívekhez
  • OfInt: A Elosztó szakosodott int
  • OfDouble: A Elosztó szentelt kettős
  • OfLong: A Elosztó szentelt hosszú

6. Következtetés

Ebben a cikkben a Java 8-at ismertettük Elosztó használat, módszerek, jellemzők, felosztási folyamat, primitív támogatás és annak testreszabása.

Mint mindig, a cikk teljes megvalósítása megtalálható a Github oldalon.