Vodič za DelayQueue

1. Pregled

U ovom ćemo članku pogledati DelayQueue konstruirati iz java.util.concurrent paket. Ovo je red za blokiranje koji se može koristiti u programima proizvođača i potrošača.

Ima vrlo korisnu karakteristiku - kada potrošač želi uzeti element iz reda, može ga uzeti tek kada je isteklo kašnjenje za taj određeni element.

2. Provedba Odloženo za Elemente u DelayQueue

Svaki element koji želimo staviti u DelayQueue treba provesti Odloženo sučelje. Recimo da želimo stvoriti DelayObject razred. Primjerci te klase bit će stavljeni u DelayQueue.

Proći ćemo Niz podataka i delayInMilliseconds kao i argumenti njegovom konstruktoru:

javna klasa DelayObject implementira odgođeni {private String podaci; privatno dugo vrijeme početka; javni DelayObject (podaci niza, dugo odgađanjeMilisekunde) {this.data = podaci; this.startTime = System.currentTimeMillis () + delayInMilliseconds; }

Mi definiramo a vrijeme početka - ovo je vrijeme kada element treba potrošiti iz reda. Dalje, moramo implementirati getDelay () metoda - trebao bi vratiti preostalo kašnjenje povezano s ovim objektom u zadanoj vremenskoj jedinici.

Stoga moramo koristiti TimeUnit.convert () metoda za vraćanje preostalog kašnjenja u pravilan Jedinica vremena:

@Override public long getDelay (jedinica vremenske jedinice) {long diff = startTime - System.currentTimeMillis (); povratna jedinica.convert (razlika, TimeUnit.MILLISECONDS); }

Kada potrošač pokuša uzeti element iz reda, DelayQueue izvršit će getDelay () kako bi saznali smije li taj element biti vraćen iz reda. Ako je getDelay () metoda će vratiti nulu ili negativan broj, što znači da bi se mogao dohvatiti iz reda.

Također moramo implementirati compareTo () metodu, jer elementi u DelayQueue sortirat će se prema vremenu isteka. Stavka koja će prvo isteći zadržava se na čelu reda, a element s najvećim vremenom isteka zadržava se na repu reda:

@Override public int compareTo (Odloženo o) {return Ints.satturedCast (this.startTime - ((DelayObject) o) .startTime); }

3. Kašnjenje u redu Cpotrošača i proizvođača

Da bismo mogli testirati naše DelayQueue moramo primijeniti logiku proizvođača i potrošača. Klasa proizvođača kao argumente uzima red, broj elemenata koje treba proizvesti i kašnjenje svake poruke u milisekundama.

Tada kad trčanje() poziva se metoda, ona stavlja elemente u red i spava 500 milisekundi nakon svakog stavljanja:

javna klasa DelayQueueProducer implementira Runnable {private BlockingQueue queue; privatni cijeli brojOfElementsToProduce; private Integer delayOfEachProducedMessageMilliseconds; // standardni konstruktor @Override public void run () {for (int i = 0; i <numberOfElementsToProduce; i ++) {DelayObject object = new DelayObject (UUID.randomUUID (). toString (), delayOfEachProducedMessageMilliseconds); System.out.println ("Stavi objekt:" + objekt); probajte {queue.put (objekt); Navoj.spavanje (500); } catch (InterruptedException tj.) {ie.printStackTrace (); }}}}

Potrošačka primjena je vrlo sličan, ali bilježi i broj konzumiranih poruka:

javna klasa DelayQueueConsumer implementira Runnable {private BlockingQueue queue; privatni cijeli brojOfElementsToTake; javni AtomicInteger numberOfConsumedElements = novi AtomicInteger (); // standardni konstruktori @Override public void run () {for (int i = 0; i <numberOfElementsToTake; i ++) {try {DelayObject object = queue.take (); numberOfConsumedElements.incrementAndGet (); System.out.println ("Potrošač uzima:" + objekt); } catch (InterruptedException e) {e.printStackTrace (); }}}}

4. DelayQueue Test upotrebe

Za testiranje ponašanja DelayQueue, stvorit ćemo jednu nit proizvođača i jednu nit potrošača.

Producent će staviti() dva objekta u red s kašnjenjem od 500 milisekundi. Test potvrđuje da je potrošač konzumirao dvije poruke:

@Test javna praznina givenDelayQueue_whenProduceElement _thenShouldConsumeAfterGivenDelay () baca InterruptedException {// dao ExecutorService izvršitelj = Executors.newFixedThreadPool (2); BlockingQueue red = novi DelayQueue (); int numberOfElementsToProduce = 2; int delayOfEachProducedMessageMilliseconds = 500; DelayQueueConsumer potrošač = novi DelayQueueConsumer (red čekanja, numberOfElementsToProduce); Proizvođač DelayQueueProducer = novi DelayQueueProducer (red čekanja, numberOfElementsToProduce, delayOfEachProducedMessageMilliseconds); // kada izvršitelj.submit (producent); izvršitelj.podnijeti (potrošač); // tada izvršilac.awaitTermination (5, TimeUnit.SECONDS); egzekutor.šutdown (); assertEquals (consumer.numberOfConsumedElements.get (), numberOfElementsToProduce); }

Možemo primijetiti da će pokretanje ovog programa dati sljedeći rezultat:

Stavite objekt: {data = '86046157-e8a0-49b2-9cbb-8326124bcab8', startTime = 1494069868007} Potrošač uzima: {data = '86046157-e8a0-49b2-9cbb-8326124bcab8', startTime = 149406986 'd47927ef-18c7-449b-b491-5ff30e6795ed', startTime = 1494069868512} Potrošač uzima: {data = 'd47927ef-18c7-449b-b491-5ff30e6795ed', startTime = 1494069868512}

Proizvođač stavlja predmet i nakon nekog vremena troši se prvi objekt za koji je isteklo kašnjenje.

Ista se situacija dogodila i za drugi element.

5. Potrošač koji nije u mogućnosti konzumirati u zadanom vremenu

Recimo da imamo proizvođača koji proizvodi element koji hoće istječu za 10 sekundi:

int numberOfElementsToProduce = 1; int delayOfEachProducedMessageMilliseconds = 10_000; DelayQueueConsumer potrošač = novi DelayQueueConsumer (red čekanja, numberOfElementsToProduce); Proizvođač DelayQueueProducer = novi DelayQueueProducer (red čekanja, numberOfElementsToProduce, delayOfEachProducedMessageMilliseconds);

Započet ćemo s testom, ali on će završiti nakon 5 sekundi. Zbog karakteristika DelayQueue, potrošač neće moći potrošiti poruku iz reda jer element još nije istekao:

izvršilac.podnijeti (producent); izvršitelj.podnijeti (potrošač); izvršitelj.awaitTermination (5, TimeUnit.SECONDS); egzekutor.šutdown (); assertEquals (consumer.numberOfConsumedElements.get (), 0);

Imajte na umu da potrošača numberOfConsumedElements ima vrijednost jednaku nuli.

6. Izrada elementa s trenutnim isticanjem

Kada su implementacije Odloženo poruka getDelay () metoda vraća negativan broj, što znači da je zadani element već istekao. U ovoj situaciji, proizvođač će odmah potrošiti taj element.

Možemo testirati situaciju stvaranja elementa s negativnim zakašnjenjem:

int numberOfElementsToProduce = 1; int delayOfEachProducedMessageMilliseconds = -10_000; DelayQueueConsumer potrošač = novi DelayQueueConsumer (red čekanja, numberOfElementsToProduce); Proizvođač DelayQueueProducer = novi DelayQueueProducer (red čekanja, numberOfElementsToProduce, delayOfEachProducedMessageMilliseconds);

Kada započnemo testni slučaj, potrošač će element odmah potrošiti jer je on već istekao:

izvršilac.podnijeti (producent); izvršitelj.podnijeti (potrošač); izvršitelj.awaitTermination (1, TimeUnit.SECONDS); egzekutor.šutdown (); assertEquals (consumer.numberOfConsumedElements.get (), 1);

7. Zaključak

U ovom smo članku gledali DelayQueue konstruirati iz java.util.concurrent paket.

Proveli smo a Odloženo element koji je proizveden i potrošen iz reda.

Iskoristili smo našu provedbu DelayQueue da konzumiraju elemente kojima je istekao rok trajanja.

Provedbu svih ovih primjera i isječaka koda možete pronaći u projektu GitHub - koji je Maven projekt, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.


$config[zx-auto] not found$config[zx-overlay] not found