Hej! I dag vil vi fortsætte med at tale om multithreading. Lad os undersøge Thread-klassen og hvad nogle få af dens metoder gør. Når vi tidligere studerede klassemetoder, skrev vi normalt bare dette: <metodenavn> -> <hvad metoden gør>.
Dette vil ikke fungere med
Lad os huske eksemplet fra den forrige lektion:
Metoden
Metoden

Thread
's metoder :) De har mere kompleks logik, som du ikke vil være i stand til at finde ud af uden et par eksempler.
Thread.start() metoden
Lad os starte med at gentage os selv. Som du sikkert husker, kan du oprette en tråd ved at få din klasse til at arve klassenThread
og tilsidesætte run()
metoden. Men det starter selvfølgelig ikke af sig selv. For at gøre dette kalder vi vores objekts start()
metode. 
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("Thread executed: " + getName());
}
}
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
Bemærk: For at starte en tråd skal du kalde den speciellestart()
metode frem forrun()
metoden! Dette er en let fejl at lave, især når du først begynder at studere multithreading. I vores eksempel, hvis du kalderrun()
metoden 10 gange i stedet forstart()
, vil du få dette:
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.run();
}
}
}
Se på resultaterne af vores program: Tråd udført: Tråd-0 Tråd udført: Tråd-1 Tråd udført: Tråd-2 Tråd udført: Tråd-3 Tråd udført: Tråd-4 Tråd udført: Tråd-5 Tråd udført: Tråd-6 Tråd udført: Tråd-7 Tråd udført: Tråd-8 Tråd udført: Tråd-9 Se på rækkefølgen af output: Alt sker i perfekt rækkefølge. Underligt, hva'? Vi er ikke vant til dette, fordi vi allerede ved, at rækkefølgen, hvori tråde startes og udføres, bestemmes af en overlegen intellekt inde i vores operativsystem: trådplanlæggeren. Måske var vi bare heldige? Det handler selvfølgelig ikke om held. Du kan bekræfte dette ved at køre programmet et par gange mere. Problemet er, at kalderun()
metode har direkte intet at gøre med multithreading. I dette tilfælde vil programmet blive udført på hovedtråden, den samme tråd som udfører metoden main()
. Den udskriver simpelthen 10 linjer successivt på konsollen, og det er det. 10 tråde er ikke startet. Så husk dette i fremtiden og tjek dig selv konstant. Hvis du ønsker, at run()
metoden skal kaldes, ring start()
. Lad os gå videre.
Thread.sleep() metoden
For at suspendere udførelsen af den aktuelle tråd i et stykke tid, bruger visleep()
metoden. 
sleep()
tager et antal millisekunder som argument, som angiver, hvor lang tid det tager at sætte tråden i dvale.
public class Main {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(3000);
System.out.println(" - How long did I sleep? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " seconds");
}
}
Konsoludgang: - Hvor længe sov jeg? - 3 sekunder Bemærk: metoden sleep()
er statisk: den holder den aktuelle tråd i dvale. Det vil sige den, der i øjeblikket bliver henrettet. Her er et andet vigtigt punkt: en sovende tråd kan blive afbrudt. I dette tilfælde kaster programmet en InterruptedException
. Vi vil overveje et eksempel nedenfor. Hvad sker der i øvrigt efter tråden vågner op? Vil det fortsætte med at blive udført lige fra hvor det slap? Nej. Efter at en tråd vågner op, dvs. den tid, der gik som et argument til, Thread.sleep()
er gået, går den over til at kunne køresstat. Men dette betyder ikke, at trådplanlæggeren kører det. Det kan meget vel give fortrinsret til en anden ikke-sovende tråd og lade vores nyvågne tråd fortsætte sit arbejde lidt senere. Sørg for at huske dette: At vågne betyder ikke at fortsætte arbejdet med det samme!
Thread.join() metoden

join()
suspenderer udførelsen af den aktuelle tråd, indtil en anden tråd afsluttes. Hvis vi har 2 tråde, t1
og t2
, og vi skriver
t1.join()
så t2
starter den ikke før t1
den er færdig. Metoden join()
kan bruges til at garantere udførelsesrækkefølgen af tråde. Lad os overveje, hvordan join()
metoden fungerer i følgende eksempel:
public class ThreadExample extends Thread {
@Override
public void run() {
System.out.println("Thread started: " + getName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread " + getName() + " is finished.");
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
ThreadExample t1 = new ThreadExample();
ThreadExample t2 = new ThreadExample();
t1.start();
/* The second thread (t2) will start running only after the first thread (t1)
is finished (or an exception is thrown) */
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
// The main thread will continue running only after t1 and t2 have finished
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("All threads have finished. The program is finished.");
}
}
Vi lavede en simpel ThreadExample
klasse. Dens opgave er at vise en besked om, at tråden er startet, falde i søvn i 5 sekunder og så endelig rapportere, at arbejdet er afsluttet. Et stykke kage. Hovedlogikken er i Main
klassen. Se på kommentarerne: vi bruger join()
metoden til at administrere trådenes eksekveringsrækkefølge. Hvis du husker, hvordan vi startede dette emne, håndteres udførelsesrækkefølgen af trådplanlæggeren. Det kører tråde efter eget skøn: hver gang på en anden måde. Her bruger vi metoden til at garantere, at t1
tråden først startes og køres først, dereftert2
tråd, og først derefter fortsætter programmets hovedtråd. Komme videre. I rigtige programmer vil du ofte finde situationer, hvor du bliver nødt til at afbryde udførelsen af en tråd. For eksempel kører vores tråd, men den venter på en bestemt begivenhed eller tilstand. Hvis det sker, stopper tråden. Det ville nok give mening, hvis der var en form for stop()
metode. Men det er ikke så enkelt. Engang havde Java faktisk en Thread.stop()
metode og tillod en tråd at blive afbrudt. Men det blev senere fjernet fra Java-biblioteket. Du kan finde den i Oracle-dokumentationen og se, at den er markeret som forældet. Hvorfor? For den stoppede bare tråden uden at gøre andet. For eksempel kan tråden arbejde med data og ændre noget. Så midt i arbejdet blev det brat og uhøjtideligt afskåret af stop()
metoden. Uden en ordentlig nedlukning eller frigivelse af ressourcer, ikke engang fejlhåndtering - der var intet af dette. For at overdrive lidt, stop()
ødelagde metoden simpelthen alt på sin måde. Det var som at trække netledningen ud af stikkontakten for at slukke for computeren. Ja, du kan få det ønskede resultat. Men alle ved, at efter et par uger vil computeren ikke takke dig for at behandle den på den måde. Det er derfor, logikken for at afbryde tråde ændrede sig i Java og bruger nu en speciel interrupt()
metode.
Thread.interrupt() metoden
Hvad sker der, hvisinterrupt()
metoden kaldes på en tråd? Der er 2 muligheder:
- Hvis objektet var i ventetilstand, for eksempel på grund af
join
ellersleep
metoderne, vil ventetiden blive afbrudt, og programmet vil kaste enInterruptedException
. - Hvis tråden var i en fungerende tilstand,
interrupted
vil det booleske flag blive sat på objektet.
Thread
klassen har boolean isInterrupted()
metoden. Lad os vende tilbage til ureksemplet, der var i en lektion i grundforløbet. For nemheds skyld har vi forenklet det lidt:
public class Clock extends Thread {
public static void main(String[] args) throws InterruptedException {
Clock clock = new Clock();
clock.start();
Thread.sleep(10000);
clock.interrupt();
}
public void run() {
Thread current = Thread.currentThread();
while (!current.isInterrupted())
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("The thread was interrupted");
break;
}
System.out.println("Tick");
}
}
}
I dette tilfælde startes uret og begynder at tikke hvert sekund. I 10. sekund afbryder vi urets tråd. Som du allerede ved, hvis tråden, som vi forsøger at afbryde, er i en af ventetilstandene, er resultatet en InterruptedException
. Dette er en kontrolleret undtagelse, så vi kan nemt fange den og udføre vores logik for at afslutte programmet. Og det er lige, hvad vi gjorde. Her er vores resultat: Tick Tick Tik Tik Tik Tik Tik Tik Tik Tik Tik Tråden blev afbrudt Dette afslutter vores introduktion til Thread
klassens vigtigste metoder. Held og lykke!
GO TO FULL VERSION