Kan køres mod kaldes i Java

1. Oversigt

Siden Java's tidlige dage har multithreading været et vigtigt aspekt af sproget. Kan køres er den centrale grænseflade, der leveres til at repræsentere opgaver med flere tråde og Kan kaldes er en forbedret version af Kan køres der blev tilføjet i Java 1.5.

I denne artikel undersøger vi forskellene og anvendelserne af begge grænseflader.

2. Udførelsesmekanisme

Begge grænseflader er designet til at repræsentere en opgave, der kan udføres af flere tråde. Kan køres opgaver kan køres ved hjælp af Tråd klasse eller ExecutorService der henviser til Callables kan kun køres ved hjælp af sidstnævnte.

3. Returneringsværdier

Lad os se nærmere på, hvordan disse grænseflader håndterer returværdier.

3.1. Med Kan køres

Det Kan køres interface er en funktionel interface og har en enkelt løb() metode, der ikke accepterer nogen parametre og ikke returnerer nogen værdier.

Dette er velegnet til situationer, hvor vi ikke leder efter et resultat af trådudførelsen, for eksempel logning af indgående begivenheder:

offentlig grænseflade Runnable {public void run (); }

Lad os forstå dette med et eksempel:

offentlig klasse EventLoggingTask implementerer Runnable {private Logger logger = LoggerFactory.getLogger (EventLoggingTask.class); @ Overstyr offentlig ugyldig kørsel () {logger.info ("Besked"); }}

I dette eksempel læser tråden bare en besked fra køen og logger den i en logfil. Der returneres ingen værdi fra opgaven; opgaven kan startes ved hjælp af ExecutorService:

public void executeTask () {executorService = Executors.newSingleThreadExecutor (); Fremtidig fremtid = executorService.submit (ny EventLoggingTask ()); executorService.shutdown (); }

I dette tilfælde er Fremtid objekt har ikke nogen værdi.

3.2. Med Kan kaldes

Det Kan kaldes interface er en generisk interface, der indeholder en enkelt opkald() metode - som returnerer en generisk værdi V:

offentlig grænseflade Kan kaldes {V-opkald () kaster Undtagelse; }

Lad os kigge på beregningen af ​​et tal:

offentlig klasse FactorialTask ​​implementerer Callable {int nummer; // standard konstruktører offentlige Heltalsopkald () kaster InvalidParamaterException {int fact = 1; // ... for (int count = number; count> 1; count -) {fact = fact * count; } returnere fakta; }}

Resultatet af opkald() metoden returneres inden for en Fremtid objekt:

@Test offentlig ugyldig nårTaskSubitted_ThenFutureResultObtained () {FactorialTask ​​opgave = ny FactorialTask ​​(5); Fremtidig fremtid = executorService.submit (opgave); assertEquals (120, future.get (). intValue ()); }

4. Undtagelse Håndtering

Lad os se, hvor egnede de er til undtagelseshåndtering.

4.1. Med Kan køres

Da metodesignaturen ikke har den "kast" -klausul, der er specificeret,der er ingen måde at udbrede yderligere kontrollerede undtagelser på.

4.2. Med Kan kaldes

Callable call () metoden indeholder “kast Undtagelse" klausul, så vi let kan udbrede kontrollerede undtagelser yderligere:

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

I tilfælde af at køre en Kan kaldes med en ExecutorService, undtagelserne er samlet i Fremtid objekt, som kan kontrolleres ved at ringe til Future.get () metode. Dette vil kaste en ExecutionException - som omslutter den oprindelige undtagelse:

@Test (forventet = ExecutionException.class) offentlig ugyldig nårException_ThenCallableThrowsIt () {FactorialCallableTask opgave = ny FactorialCallableTask (-5); Fremtidig fremtid = executorService.submit (opgave); Heltalsresultat = future.get (). IntValue (); }

I ovenstående test er ExecutionException bliver kastet, da vi passerer et ugyldigt nummer. Vi kan ringe til getCause () metode på dette undtagelsesobjekt for at få den oprindelige kontrollerede undtagelse.

Hvis vi ikke ringer til få() metode til Fremtid klasse - så undtagelsen kastet af opkald() metode rapporteres ikke tilbage, og opgaven markeres stadig som afsluttet:

@Test offentlig ugyldig nårException_ThenCallableDoesntThrowsItIfGetIsNotCalled () {FactorialCallableTask task = new FactorialCallableTask (-5); Fremtidig fremtid = executorService.submit (opgave); assertEquals (false, future.isDone ()); }

Ovenstående test vil bestå med succes, selvom vi har kastet en undtagelse for de negative værdier af parameteren til FaktorCallableTask.

5. Konklusion

I denne artikel har vi undersøgt forskellene mellem Kan køres og Kan kaldes grænseflader.

Som altid er den komplette kode til denne artikel tilgængelig på GitHub.