Hvorfor ikke starte en tråd i konstruktøren?

1. Oversigt

I denne hurtige vejledning skal vi se, hvorfor vi ikke skal starte en tråd inde i en konstruktør.

Først introducerer vi kort publikationskonceptet i Java og JVM. Derefter ser vi, hvordan dette koncept påvirker den måde, vi starter tråde på.

2. Offentliggørelse og flugt

Hver gang vi gør et objekt tilgængeligt for enhver anden kode uden for dets nuværende anvendelsesområde, offentliggør vi grundlæggende det objekt. For eksempel sker udgivelse, når vi returnerer et objekt, gemmer det i et offentlig reference, eller endda videregive den til en anden metode.

Når vi offentliggør et objekt, som vi ikke burde have, siger vi, at objektet er undsluppet.

Der er mange måder, hvorpå vi kan lade et objekt henvise undslippe, såsom at offentliggøre objektet inden dets fulde konstruktion. Faktisk er dette en af ​​de almindelige former for flugt: når det her reference undslipper under objektkonstruktion.

Når det her reference undslipper under konstruktion, kan andre tråde se det objekt i en forkert og ikke fuldt konstrueret tilstand. Dette kan igen forårsage underlige trådsikkerhedskomplikationer.

3. Undslippe med tråde

En af de mest almindelige måder at lade det her reference escape er at starte en tråd i en konstruktør. Lad os overveje et eksempel for bedre at forstå dette:

public class LoggerRunnable implementerer Runnable {public LoggerRunnable () {Thread thread = new Thread (this); // dette undgår thread.start (); } @ Override public void run () {System.out.println ("Started ..."); }}

Her passerer vi eksplicit det her henvisning til Tråd konstruktør. Derfor, den nystartede tråd kan muligvis se det medfølgende objekt, før dets fulde konstruktion er afsluttet. I samtidige sammenhænge kan dette forårsage subtile bugs.

Det er også muligt at passere det her henvisning implicit:

offentlig klasse ImplicitEscape {public ImplicitEscape () {Thread t = new Thread () {@Override public void run () {System.out.println ("Started ..."); }}; t.start (); }}

Som vist ovenfor opretter vi en anonym indre klasse afledt af Tråd. Da indre klasser opretholder en henvisning til deres lukkede klasse, er det her reference slipper igen fra konstruktøren.

Der er intet iboende galt med at oprette en Tråd inde i en konstruktør. Det er dog meget modløs at starte det med det samme, som det meste af tiden ender vi med en undsluppet det her enten eksplicit eller implicit.

3.1. Alternativer

I stedet for at starte en tråd inde i en konstruktør, kan vi erklære en dedikeret metode til dette scenario:

offentlig klasse SafePublication implementerer Runnable {private final Thread thread; offentlig SafePublication () {tråd = ny tråd (denne); } @ Override public void run () {System.out.println ("Started ..."); } offentlig ugyldig start () {thread.start (); }} ;:

Som vist ovenfor offentliggør vi stadig det her henvisning til Tråd. Denne gang starter vi imidlertid tråden, når konstruktøren vender tilbage:

SafePublication-publikation = ny SafePublication (); publikation.start ();

Derfor slipper objektreferencen ikke til en anden tråd før dens fulde konstruktion.

4. Konklusion

I denne hurtige vejledning så vi efter en kort introduktion til den sikre publikation, hvorfor vi ikke skulle starte en tråd inde i en konstruktør.

Mere detaljerede oplysninger om offentliggørelse og flugt i Java findes i Java Concurrency in Practice-bogen.

Som sædvanligt er alle eksemplerne tilgængelige på GitHub.