Druk even en oneven nummers af met 2 draden

1. Inleiding

In deze tutorial gaan we kijken hoe we even en oneven getallen kunnen afdrukken met twee threads.

Het doel is om de nummers op volgorde af te drukken, terwijl de ene draad alleen de even nummers afdrukt en de andere draad alleen de oneven nummers. We zullen de concepten van thread-synchronisatie en inter-thread-communicatie gebruiken om het probleem op te lossen.

2. Discussies in Java

Threads zijn lichtgewicht processen die gelijktijdig kunnen worden uitgevoerd. Gelijktijdige uitvoering van meerdere threads kan goed zijn wat betreft prestaties en CPU-gebruik, omdat we aan meer dan één taak tegelijk kunnen werken via verschillende parallel lopende threads.

Meer informatie over threads in Java vindt u in dit artikel.

In Java kunnen we een thread maken door de extensie Draad class of door het implementeren van de Runnable koppel. In beide gevallen overschrijven we de rennen methode en schrijf de implementatie van de thread erin.

Meer informatie over het gebruik van deze methoden om een ​​thread te maken, vindt u hier.

3. Thread-synchronisatie

In een omgeving met meerdere threads is het mogelijk dat 2 of meer threads tegelijkertijd toegang hebben tot dezelfde bron. Dit kan fataal zijn en tot foutieve resultaten leiden. Om dit te voorkomen, moeten we ervoor zorgen dat slechts één thread op een bepaald moment toegang heeft tot de bron.

We kunnen dit bereiken met behulp van thread-synchronisatie.

In Java kunnen we een methode of blok markeren als gesynchroniseerd, wat betekent dat slechts één thread die methode of blok op een bepaald moment kan invoeren.

Meer details over thread-synchronisatie in Java vindt u hier.

4. Inter-Thread-communicatie

Inter-thread-communicatie zorgt ervoor dat gesynchroniseerde threads met elkaar kunnen communiceren via een reeks methoden.

De gebruikte methoden zijn wacht, melden, en verwittigenAll, die allemaal zijn geërfd van de Voorwerp klasse.

Wacht() zorgt ervoor dat de huidige thread voor onbepaalde tijd wacht totdat een andere thread wordt aangeroepen meld () of meldAll () op hetzelfde object. We kunnen bellen melden () om threads wakker te maken die wachten op toegang tot de monitor van dit object.

Meer informatie over de werking van deze methoden vindt u hier.

5. Alternatief afdrukken van oneven en even nummers

5.1. Gebruik makend van wacht() en melden ()

We zullen de besproken concepten van synchronisatie en communicatie tussen threads gebruiken om oneven en even getallen in oplopende volgorde af te drukken met behulp van twee verschillende threads.

In de eerste stap implementeren we het Runnable interface om de logica van beide threads te definiëren. In de rennen methode controleren we of het getal even of oneven is.

Als het nummer even is, bellen we de printEven methode van de Printer klasse, anders noemen we de printOdd methode:

klasse TaskEvenOdd implementeert Runnable {private int max; particuliere printer afdrukken; private boolean isEvenNumber; // standard constructors @Override public void run () {int number = isEvenNumber? 2: 1; while (nummer <= max) {if (isEvenNumber) {print.printEven (nummer); } else {print.printOdd (nummer); } getal + = 2; }}} 

We definiëren de Printer klasse als volgt:

klasse Printer {privé vluchtige boolean isOdd; gesynchroniseerde ongeldige printEven (int nummer) {while (! isOdd) {try {wait (); } catch (InterruptedException e) {Thread.currentThread (). interrupt (); }} System.out.println (Thread.currentThread (). GetName () + ":" + nummer); isOdd = false; melden (); } gesynchroniseerde ongeldige printOdd (int nummer) {while (isOdd) {probeer {wait (); } catch (InterruptedException e) {Thread.currentThread (). interrupt (); }} System.out.println (Thread.currentThread (). GetName () + ":" + nummer); isOdd = waar; melden (); }}

In de hoofdmethode gebruiken we de gedefinieerde klasse om twee threads te maken. We maken een object van de Printer class en geef deze als parameter door aan de TaskEvenOdd constructeur:

public static void main (String ... args) {Printer print = nieuwe Printer (); Thread t1 = new Thread (nieuwe TaskEvenOdd (print, 10, false), "Odd"); Thread t2 = new Thread (new TaskEvenOdd (print, 10, true), "Even"); t1.start (); t2.start (); }

De eerste thread is de oneven thread, dus we passeren false als de waarde van de parameter isEvenNumber. Voor de tweede thread passeren we waar in plaats daarvan. We stellen de maximum waarde tot 10 voor beide draden, zodat alleen de nummers van 1 tot en met 10 worden afgedrukt.

We starten dan beide threads door de begin() methode. Dit roept het rennen() methode van beide threads zoals hierboven gedefinieerd, waarbij we controleren of het aantal oneven of even is en ze afdrukken.

Wanneer de oneven thread begint te lopen, wordt de waarde van de variabele aantal wordt 1. Omdat het minder is dan de maximum waarde en de vlag isEvenNumber is fout, printOdd () wordt genoemd. In de methode controleren we of de vlag is vreemd is waar en hoewel het waar is, bellen we wacht(). Sinds is vreemd aanvankelijk vals is, wacht() wordt niet aangeroepen en de waarde wordt afgedrukt.

Vervolgens stellen we de waarde in van is vreemd naar true, zodat de oneven thread in de wachttoestand gaat en aanroept melden () om de gelijkmatige draad wakker te maken. De even draad wordt dan wakker en drukt het even getal af sinds de vreemd vlag is onwaar. Het roept dan melden () om de oneven draad wakker te maken.

Hetzelfde proces wordt uitgevoerd tot de waarde van de variabele aantal is groter dan de maximum waarde.

5.2. Semaforen gebruiken

Een semafoor regelt de toegang tot een gedeelde bron door middel van een teller. Als het teller is groter dan nul, dan is toegang toegestaan. Als het nul is, wordt de toegang geweigerd.

Java biedt het Semafoor klasse in de java.util.concurrent pakket en we kunnen het gebruiken om het toegelichte mechanisme te implementeren. Meer details over semaforen zijn hier te vinden.

We maken twee draden, een oneven draad en een even draad. De oneven thread drukt de oneven nummers af vanaf 1, en de even thread print de even nummers vanaf 2.

Beide draden hebben een voorwerp van de Gedeelde printer klasse. De Gedeelde printer klasse heeft twee semaforen, semOdd en semEven die om te beginnen 1 en 0 vergunningen hebben. Dit zorgt ervoor dat het oneven aantal als eerste wordt afgedrukt.

We hebben twee methoden printEvenNum () en printOddNum (). De oneven thread noemt de printOddNum () methode en de even thread roept de printEvenNum () methode.

Om een ​​oneven nummer af te drukken, de verkrijgen() methode wordt aangeroepen semOdd, en aangezien de initiële vergunning 1 is, verkrijgt het de toegang met succes, drukt het oneven nummer af en belt vrijlating() Aan semEven.

Roeping vrijlating() verhoogt de vergunning met 1 voor semEven, en de even thread kan dan met succes de toegang verkrijgen en het even nummer afdrukken.

Dit is de code voor de hierboven beschreven workflow:

public static void main (String [] args) {SharedPrinter sp = nieuwe SharedPrinter (); Thread oneven = nieuwe Thread (new Odd (sp, 10), "Odd"); Thread even = nieuwe Thread (new Even (sp, 10), "Even"); odd.start (); even.start (); }
class SharedPrinter {private Semaphore semEven = new Semaphore (0); private Semaphore semOdd = nieuwe Semaphore (1); void printEvenNum (int num) {probeer {semEven.acquire (); } catch (InterruptedException e) {Thread.currentThread (). interrupt (); } System.out.println (Thread.currentThread (). GetName () + num); semOdd.release (); } void printOddNum (int num) {probeer {semOdd.acquire (); } catch (InterruptedException e) {Thread.currentThread (). interrupt (); } System.out.println (Thread.currentThread (). GetName () + num); semEven.release (); }} class Zelfs implementeert Runnable {private SharedPrinter sp; privé int max; // standaard constructor @Override public void run () {for (int i = 2; i <= max; i = i + 2) {sp.printEvenNum (i); }}} klasse Odd implementeert Runnable {private SharedPrinter sp; privé int max; // standard constructors @Override public void run () {for (int i = 1; i <= max; i = i + 2) {sp.printOddNum (i); }}}

6. Conclusie

In deze tutorial hebben we bekeken hoe we oneven en even getallen afwisselend kunnen afdrukken met twee threads in Java. We hebben twee methoden bekeken om dezelfde resultaten te bereiken: gebruik makend van wacht() en melden () en gebruik maken van een Semafoor.

En, zoals altijd, is de volledige werkende code beschikbaar op GitHub.