Implementere en kjørbar vs å utvide en tråd

1. Introduksjon

“Bør jeg implementere en Kjørbar eller utvide Tråd klasse"? er ganske vanlig spørsmål.

I denne artikkelen vil vi se hvilken tilnærming som gir mer mening i praksis og hvorfor.

2. Bruke Tråd

La oss først definere en Enkel tråd klasse som strekker seg Tråd:

offentlig klasse SimpleThread utvider tråd {privat strengmelding; // standard logger, constructor @Override public void run () {log.info (melding); }}

La oss også se hvordan vi kan kjøre en tråd av denne typen:

@Test offentlig ugyldighet gittAThread_whenRunIt_thenResult () kaster unntak {Thread thread = new SimpleThread ("SimpleThread utført ved hjelp av Thread"); thread.start (); thread.join (); }

Vi kan også bruke en ExecutorService å utføre tråden:

@Test offentlig ugyldighet gittAThread_whenSubmitToES_thenResult () kaster unntak {executorService.submit (ny SimpleThread ("SimpleThread utført ved hjelp av ExecutorService")). Get (); }

Det er ganske mye kode for å kjøre en enkelt loggoperasjon i en egen tråd.

Vær også oppmerksom på at Enkel tråd kan ikke utvide noen annen klasse, da Java ikke støtter flere arv.

3. Implementering a Kjørbar

La oss nå lage en enkel oppgave som implementerer java.lang.Runnable grensesnitt:

klasse SimpleRunnable implementerer Runnable {privat strengmelding; // standard logger, constructor @Override public void run () {log.info (melding); }}

Ovennevnte SimpleRunnable er bare en oppgave som vi vil kjøre i en egen tråd.

Det er forskjellige tilnærminger vi kan bruke for å kjøre den; en av dem er å bruke Tråd klasse:

@Test offentlig ugyldig givenRunnable_whenRunIt_thenResult () kaster unntak {Thread thread = new Thread (new SimpleRunnable ("SimpleRunnable executed using Thread")); thread.start (); thread.join (); }

Vi kan til og med bruke en ExecutorService:

@Test offentlig ugyldighet gittARunnable_whenSubmitToES_thenResult () kaster unntak {executorService.submit (ny SimpleRunnable ("SimpleRunnable utført ved hjelp av ExecutorService")). Get (); }

Vi kan lese mer om ExecutorService her inne.

Siden vi nå implementerer et grensesnitt, kan vi utvide en annen basisklasse hvis vi trenger det.

Fra og med Java 8 behandles ethvert grensesnitt som avslører en enkelt abstrakt metode som et funksjonelt grensesnitt, noe som gjør det til et gyldig mål for lambdauttrykk.

Vi kan omskrive det ovennevnte Kjørbar kode ved hjelp av et lambdauttrykk:

@Test offentlig ugyldighet gittARunnableLambda_whenSubmitToES_thenResult () kaster Unntak {executorService.submit (() -> log.info ("Lambda kjørbar utført!")); }

4. Kjørbar eller Tråd?

Enkelt sagt, vi oppfordrer generelt til bruk av Kjørbar over Tråd:

  • Når du utvider Tråd klasse overstyrer vi ikke noen av metodene. I stedet overstyrer vi metoden for Kjørbar (hvilken Tråd skjer for å implementere). Dette er et klart brudd på IS-A Tråd prinsipp
  • Lage en implementering av Kjørbar og overføre den til Tråd klasse bruker komposisjon og ikke arv - som er mer fleksibel
  • Etter å ha utvidet Tråd klasse, kan vi ikke utvide noen annen klasse
  • Fra Java 8 og utover, Runnables kan representeres som lambdauttrykk

5. Konklusjon

I denne raske opplæringen så vi hvordan implementering Kjørbar er vanligvis en bedre tilnærming enn å utvide Tråd klasse.

Koden for dette innlegget finner du på GitHub.