Runnable vs. Callable in Java

overzicht

sinds het begin van Java is multithreading een belangrijk aspect van de taal geweest. Runnable is de kerninterface voor het vertegenwoordigen van multi-threaded taken en Callable is een verbeterde versie van Runnable die werd toegevoegd in Java 1.5.

In dit artikel zullen we de verschillen en de toepassingen van beide interfaces onderzoeken.

Uitvoermechanisme

beide interfaces zijn ontworpen om een taak weer te geven die met meerdere threads kan worden uitgevoerd. Uitvoerbare taken kunnen worden uitgevoerd met behulp van de Thread class of ExecutorService, terwijl Callables kan worden uitgevoerd alleen met behulp van de laatste.

Return Values

laten we eens een diepere blik op de manier waarop deze interfaces omgaan met return values.

3.1. Met Runnable

is de Runnable interface een functionele interface en heeft een single run () methode die geen parameters accepteert en geen waarden retourneert.

dit is geschikt voor situaties waarin we niet op zoek zijn naar een resultaat van de thread-uitvoering, bijvoorbeeld het loggen van inkomende gebeurtenissen:

public interface Runnable { public void run();}

laten we dit begrijpen met een voorbeeld:

public class EventLoggingTask implements Runnable{ private Logger logger = LoggerFactory.getLogger(EventLoggingTask.class); @Override public void run() { logger.info("Message"); }}

In dit voorbeeld leest de thread gewoon een bericht uit de wachtrij en logt het in een logbestand. Er wordt geen waarde geretourneerd van de taak; de taak kan worden gestart met behulp van ExecutorService:

public void executeTask() { executorService = Executors.newSingleThreadExecutor(); Future future = executorService.submit(new EventLoggingTask()); executorService.shutdown();}

In dit geval zal het toekomstige object geen waarde hebben.

3.2. Met Callable

is de Callable interface een generieke interface die een single call() methode bevat-die een generieke waarde V retourneert:

public interface Callable<V> { V call() throws Exception;}

laten we eens kijken naar het berekenen van de faculteit van een getal:

public class FactorialTask implements Callable<Integer> { int number; // standard constructors public Integer call() throws InvalidParamaterException { int fact = 1; // ... for(int count = number; count > 1; count--) { fact = fact * count; } return fact; }}

het resultaat van de call () – methode wordt binnen een toekomstig object geretourneerd:

@Testpublic void whenTaskSubmitted_ThenFutureResultObtained(){ FactorialTask task = new FactorialTask(5); Future<Integer> future = executorService.submit(task); assertEquals(120, future.get().intValue());}

Exception Handling

laten we eens kijken hoe geschikt ze zijn voor exception handling.

4.1. Met Runnable

omdat de methodehandtekening niet de” gooit ” – clausule heeft gespecificeerd, is er geen manier om verdere gecontroleerde uitzonderingen door te geven.

4.2. Met Callable

Callable ’s call() methode bevat” gooit uitzondering ” clausule, zodat we gemakkelijk gecheckte uitzonderingen verder kunnen verspreiden:

public class FactorialTask implements Callable<Integer> { // ... public Integer call() throws InvalidParamaterException { if(number < 0) { throw new InvalidParamaterException("Number should be positive"); } // ... }}

in het geval van het uitvoeren van een Callable met behulp van een ExecutorService, worden de uitzonderingen verzameld in het object Future, dat kan worden gecontroleerd door een call naar de Future uit te voeren.get () methode. Dit zal gooien een ExecutionException-die wraps de oorspronkelijke uitzondering:

@Test(expected = ExecutionException.class)public void whenException_ThenCallableThrowsIt() { FactorialCallableTask task = new FactorialCallableTask(-5); Future<Integer> future = executorService.submit(task); Integer result = future.get().intValue();}

in de bovenstaande test, de Executionexceptie wordt gegooid als we het passeren van een ongeldig nummer. We kunnen de methode getCause() op dit exception object aanroepen om de originele aangevinkte uitzondering te krijgen.

als we de call niet maken naar de get() methode van Future class-dan zal de exception thrown by call() methode niet worden gerapporteerd, en de taak zal nog steeds worden gemarkeerd als voltooid:

@Testpublic void whenException_ThenCallableDoesntThrowsItIfGetIsNotCalled(){ FactorialCallableTask task = new FactorialCallableTask(-5); Future<Integer> future = executorService.submit(task); assertEquals(false, future.isDone());}

de bovenstaande test zal succesvol slagen, ook al hebben we een uitzondering voor de negatieve waarden van de parameter naar FactorialCallableTask gegooid.

conclusie

In dit artikel hebben we de verschillen onderzocht tussen de Runnable en Callable interfaces.

Zoals altijd is de volledige code voor dit artikel beschikbaar op GitHub.

aan de slag met Spring 5 en Spring Boot 2, Via de learn Spring course:

>> bekijk de cursus

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.

Previous post Nitril
Next post magnesium chloride MgCl2 calciumchloride CaCl2 ionische binding Lewis 2D dot & cross electronic diagrams 3D ball & stick close packed space filling models crystal lattice smeltpunt ionische binding compound Doc Brown ’s chemistry revision notes