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.