4 Methoden voor schrijven van code met meerdere threads in Java

4 Methoden voor schrijven van code met meerdere threads in Java / Programming

Multi-threading is een methode om code te schrijven voor het tegelijkertijd uitvoeren van taken. Java heeft uitstekende ondersteuning gehad voor het schrijven van multi-threaded code sinds de begintijd van Java 1.0. Recente verbeteringen aan Java hebben de manieren waarop code kan worden gestructureerd om multi-threading op te nemen in Java-programma's te vergroten.

In dit artikel vergelijken we enkele van deze opties, zodat u beter kunt beoordelen welke optie u wilt gebruiken voor uw volgende Java-project Love GitHub? 4 redenen waarom u uw code moet hosten op BitBucket Love GitHub? 4 redenen waarom u uw code moet hosten op BitBucket U moet bedenken waar u uw code wilt opslaan. Het is waarschijnlijk dat je hebt gehoord van GitHub. Dat is niet verrassend. GitHub wordt door particulieren en bedrijven gebruikt om code te hosten, samen te werken aan documentatie ... Lees meer t.

Methode 1: De Thread-klasse uitbreiden

Java biedt een Draad klasse die kan worden uitgebreid om het rennen() methode. Met deze methode run () implementeert u uw taak. Wanneer u de taak in zijn eigen thread wilt starten, kunt u een exemplaar van deze klasse maken en de bijbehorende aanroepen begin() methode. Hiermee wordt de uitvoering van de thread gestart en wordt deze uitgevoerd (of wordt een uitzondering gemaakt).

Hier is een eenvoudige Thread-klasse die slechts gedurende een opgegeven interval slaapt als een manier om een ​​langlopende bewerking te simuleren.

public class MyThread breidt Thread uit private int sleepFor; openbare MyThread (int sleepFor) this.sleepFor = sleepFor;  @Override public void run () System.out.printf ("[% s] thread beginnend \ n", Thread.currentThread (). ToString ()); probeer Thread.sleep (this.sleepFor);  catch (InterruptedException ex)  System.out.printf ("[% s] thread ending \ n", Thread.currentThread (). toString ());  

Maak een instantie van deze Thread-klasse door deze het aantal milliseconden te laten inslapen.

MyThread-medewerker = nieuwe MyThread (sleepFor); 

Begin met het uitvoeren van deze werkthread door de start () -methode aan te roepen. Met deze methode wordt de controle onmiddellijk naar de beller teruggestuurd, zonder te wachten totdat de thread wordt beëindigd.

worker.start (); System.out.printf ("[% s] thread \ n", Thread.currentThread (). ToString ()); 

En hier is de uitvoer van het uitvoeren van deze code. Dit geeft aan dat de diagnostische hoofddraaddiagnose wordt afgedrukt voordat de werkthread wordt uitgevoerd.

[Discussie [hoofd, 5, hoofd]] hoofdthread [Thread [Thread-0,5, main]] thread starting [Thread [Thread-0,5, main]] thread ending 

Aangezien er geen instructies meer zijn nadat de werkthread is gestart, wacht de hoofdthread totdat de werkthread is voltooid voordat het programma wordt afgesloten. Hierdoor kan de werkthread zijn taak voltooien.

Methode 2: een Thread-instantie gebruiken met een werkbare

Java biedt ook een interface genaamd uitvoerbare welke door een arbeidersklasse kan worden geïmplementeerd om de taak in zijn rennen() methode. Dit is een alternatieve manier om een ​​arbeidersklasse te maken in plaats van het uitbreiden van de Draad klasse (hierboven beschreven).

Hier is de implementatie van de arbeidersklasse die nu Runnable implementeert in plaats van Thread uit te breiden.

public class MyThread2 implementeert Runnable // same als hierboven 

Het voordeel van het implementeren van de Runnable-interface in plaats van het uitbreiden van de Thread-klasse, is dat de werksetklasse nu een domeinspecifieke klasse kan uitbreiden binnen een klassenhiërarchie.

Wat betekent dit?

Laten we bijvoorbeeld zeggen dat u een Fruit klasse die bepaalde generieke kenmerken van fruit implementeert. Nu wil je een implementeren Papaja klasse die bepaalde fruitkenmerken specialiseert. U kunt dat doen door de Papaja klasse verlengen de Fruit klasse.

public class Fruit // fruitspecifieke kenmerken hier public class Papaya breidt Fruit hier uit met betrekking tot // negeren gedrag specifiek voor papaya 

Stel nu dat je een tijdrovende taak hebt die Papaya moet ondersteunen, die je in een aparte thread kunt uitvoeren. Dit geval kan worden afgehandeld door de Papaya-klasse Runnable te laten implementeren en de methode run () aan te bieden waar deze taak wordt uitgevoerd.

public class Papaya breidt Fruit-implementaties uit Runnable // override-gedrag specifiek voor papaya hier @Override public void run () // tijdrovende taak hier.  

Om de werkthread af te stemmen, maakt u een instantie van de werksetklasse en geeft u deze bij het maken door aan een Thread-instantie. Wanneer de methode start () van de thread wordt aangeroepen, wordt de taak in een afzonderlijke thread uitgevoerd.

Papaya papaya = nieuwe Papaya (); // stel eigenschappen in en roep papaya-methoden hier op. Thread thread = new Thread (papaya); thread.start (); 

En dat is een korte samenvatting van het gebruik van een Runnable om een ​​taak uit te voeren die binnen een thread wordt uitgevoerd.

Methode 3: uitvoeren van een Runnable With ExecutorService

Vanaf versie 1.5 biedt Java een ExecutorService als een nieuw paradigma voor het maken en beheren van threads binnen een programma. Het generaliseert het concept van thread-uitvoering door creatie van threads te abstraheren.

Dit komt omdat u uw taken binnen een pool van threads kunt uitvoeren net zo gemakkelijk als het gebruik van een afzonderlijke thread voor elke taak. Hierdoor kan uw programma bijhouden en beheren hoeveel threads worden gebruikt voor werknemertaken.

Stel dat u een 100-werktaken hebt die wachten om te worden uitgevoerd. Als u één thread per werknemer start (zoals hierboven weergegeven), heeft u 100 threads in uw programma die kunnen leiden tot knelpunten elders in het programma. In plaats daarvan, als u een threadpool gebruikt met, bijvoorbeeld 10 threads vooraf toegewezen, worden uw 100 taken één voor één door deze threads uitgevoerd, zodat uw programma niet uitgehongerd is voor bronnen. Bovendien kunnen deze thread-threads voor threads worden geconfigureerd zodat ze rondhangen om extra taken voor u uit te voeren.

Een ExecutorService accepteert een uitvoerbare taak (hierboven uitgelegd) en voert de taak op een geschikt moment uit. De submit () methode, die de werkbare taak accepteert, retourneert een exemplaar van een klasse genaamd Toekomst, waarmee de beller de status van de taak kan volgen. In het bijzonder, de krijgen() methode laat de beller toe te wachten tot de taak is voltooid (en levert de eventuele retourcode op).

In het onderstaande voorbeeld maken we een ExecutorService met behulp van de statische methode newSingleThreadExecutor (), die zoals de naam aangeeft, een enkele thread creëert voor het uitvoeren van taken. Als er meer taken worden ingediend terwijl een taak wordt uitgevoerd, maakt de ExecutorService deze taken in een wachtrij voor latere uitvoering.

De implementeerbare Runtable-implementatie die we hier gebruiken, is dezelfde als hierboven beschreven.

ExecutorService esvc = Executors.newSingleThreadExecutor (); Uitvoerbare werknemer = nieuwe MyThread2 (sleepFor); Toekomst future = esvc.submit (worker); System.out.printf ("[% s] thread \ n", Thread.currentThread (). ToString ()); future.get (); esvc.shutdown (); 

Merk op dat een ExecutorService correct moet worden afgesloten als deze niet langer nodig is voor verdere taakinzendingen.

Methode 4: Een opvraagbare gebruikt met ExecutorService

Vanaf versie 1.5 introduceerde Java een nieuwe interface genaamd Callable. Het is vergelijkbaar met de oudere Runnable-interface met het verschil dat de uitvoeringsmethode (genaamd () aanroepen in plaats van rennen()) kan een waarde retourneren. Bovendien kan het ook verklaren dat een Uitzondering kan worden gegooid.

Een ExecutorService kan ook taken accepteren die zijn geïmplementeerd als Callable en retourneert een Toekomst met de waarde geretourneerd door de methode bij voltooiing.

Hier is een voorbeeld Mango klasse die het. uitbreidt Fruit klasse eerder gedefinieerd en implementeert de Callable interface. Een kostbare en tijdrovende taak wordt uitgevoerd binnen de () aanroepen methode.

public class Mango breidt Fruit-implementaties Callable uit public Integer call () // dure berekening hier retourneer nieuw geheel getal (0);  

En hier is de code voor het indienen van een exemplaar van de klasse bij een ExecutorService. De onderstaande code wacht ook tot de taak is voltooid en de retourwaarde wordt afgedrukt.

ExecutorService esvc = Executors.newSingleThreadExecutor (); MyCallable worker = new MyCallable (sleepFor); Future future = esvc.submit (worker); System.out.printf ("[% s] thread \ n", Thread.currentThread (). ToString ()); System.out.println ("Teruggestuurde taak:" + future.get ()); esvc.shutdown (); 

Wat verkies je?

In dit artikel hebben we enkele methoden geleerd om code met meerdere threads in Java te schrijven. Waaronder:

  1. Het uitbreiden van de Draad klasse is de meest elementaire en is beschikbaar vanaf Java 1.0.
  2. Als u een klasse hebt die een andere klasse in een klassenhiërarchie moet uitbreiden, dan kunt u de uitvoerbare interface.
  3. Een modernere voorziening voor het maken van discussielijnen is de ExecutorService die een Runnable-instantie kan accepteren als een uit te voeren taak. Het voordeel van deze methode is dat u een threadpool kunt gebruiken voor taakuitvoering. Een threadpool helpt bij het behoud van hulpbronnen door threads opnieuw te gebruiken.
  4. Ten slotte kunt u ook een taak maken door de Callable interface en het indienen van de taak bij een ExecutorService.

Welke van deze opties denk je dat je gaat gebruiken in je volgende project? Laat het ons weten in de comments hieronder.

Ontdek meer over: Java.