Hej! Idag ska vi fortsÀtta att prata om multithreading. LÄt oss undersöka klassen Thread och vad nÄgra av dess metoder gör. NÀr vi tidigare studerat klassmetoder skrev vi oftast bara detta: <metodnamn> -> <vad metoden gör>.
Detta kommer inte att fungera med
LÄt oss komma ihÄg exemplet frÄn föregÄende lektion:
Metoden
Metoden

Thread
's metoder :) De har mer komplex logik som du inte kommer att kunna lista ut utan nÄgra exempel.
Metoden Thread.start()
LÄt oss börja med att upprepa oss sjÀlva. Som du sÀkert minns kan du skapa en trÄd genom att fÄ din klass att Àrva klassenThread
och ÄsidosÀtta run()
metoden. Men det startar inte sjÀlvklart. För att göra detta kallar vi vÄrt objekts start()
metod. 
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();
}
}
}
Obs: För att starta en trÄd mÄste du anropa specialmetodenstart()
snarare Ànrun()
metoden! Detta Àr ett lÀtt fel att göra, speciellt nÀr du först börjar studera multithreading. I vÄrt exempel, om du anroparrun()
metoden 10 gÄnger istÀllet förstart()
, skulle du fÄ detta:
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.run();
}
}
}
Titta pÄ resultatet av vÄrt program: TrÄd utförd: TrÄd-0 TrÄd utförd: TrÄd-1 TrÄd utförd: TrÄd-2 TrÄd utförd: TrÄd-3 TrÄd utförd: TrÄd-4 TrÄd utförd: TrÄd-5 TrÄd utförd: TrÄd-6 TrÄd utförd: TrÄd-7 TrÄd utförd: TrÄd-8 TrÄd utförd: TrÄd-9 Titta pÄ ordningen för utdata: Allt hÀnder i perfekt ordning. Konstigt va? Vi Àr inte vana vid detta, eftersom vi redan vet att ordningen i vilken trÄdar startas och körs bestÀms av en överlÀgsen intellekt i vÄrt operativsystem: trÄdschemalÀggaren. Vi kanske bara hade tur? Naturligtvis handlar det inte om tur. Du kan verifiera detta genom att köra programmet ett par gÄnger till. Problemet Àr att ringarun()
Metoden har direkt inget med multithreading att göra. I det hÀr fallet kommer programmet att köras pÄ huvudtrÄden, samma trÄd som kör metoden main()
. Den skriver helt enkelt ut 10 rader pÄ konsolen successivt och det Àr allt. 10 trÄdar har inte startat. SÄ kom ihÄg detta i framtiden och kontrollera dig sjÀlv hela tiden. Om du vill att run()
metoden ska anropas, ring start()
. LÄt oss gÄ lÀngre.
Metoden Thread.sleep()
För att avbryta exekveringen av den aktuella trÄden ett tag anvÀnder visleep()
metoden. 
sleep()
tar ett antal millisekunder som ett argument, vilket anger hur lÄng tid det tar att lÀgga trÄden i vilolÀge.
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");
}
}
KonsolutgÄng: - Hur lÀnge sov jag? - 3 sekunder Obs: metoden sleep()
Àr statisk: den sover den aktuella trÄden. Det vill sÀga den som för nÀrvarande avrÀttas. HÀr Àr en annan viktig punkt: en sovande trÄd kan avbrytas. I det hÀr fallet kastar programmet en InterruptedException
. Vi kommer att övervÀga ett exempel nedan. Förresten, vad hÀnder efter att trÄden vaknar? Kommer det att fortsÀtta att utföras precis dÀr det slutade? Nej. Efter att en trÄd vaknar, dvs tiden som gÄtt som ett argument till Thread.sleep()
har gÄtt, övergÄr den till körbarstat. Men detta betyder inte att trÄdschemalÀggaren kommer att köra den. Det kan mycket vÀl ge företrÀde Ät nÄgon annan icke-sovande trÄd och lÄta vÄr nyvÀckta trÄd fortsÀtta sitt arbete lite senare. Var noga med att komma ihÄg detta: att vakna betyder inte att fortsÀtta arbeta omedelbart!
Metoden Thread.join()

join()
avbryter exekveringen av den aktuella trĂ„den tills en annan trĂ„d avslutas. Om vi ââhar 2 trĂ„dar, t1
och t2
, och vi skriver
t1.join()
startar sedan t2
inte förrÀn t1
det Àr klart. Metoden join()
kan anvÀndas för att garantera exekveringsordningen för trÄdar. LÄt oss övervÀga hur join()
metoden fungerar i följande exempel:
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 skapade en enkel ThreadExample
klass. Dess uppgift Àr att visa ett meddelande om att trÄden har startat, somna i 5 sekunder och sedan slutligen rapportera att arbetet Àr klart. LÀtt som en plÀtt. Huvudlogiken ligger i Main
klassen. Titta pÄ kommentarerna: vi anvÀnder join()
metoden för att framgÄngsrikt hantera trÄdarnas exekveringsorder. Om du kommer ihÄg hur vi startade detta Àmne, hanteras exekveringsordningen av trÄdschemalÀggaren. Den driver trÄdar efter eget gottfinnande: varje gÄng pÄ ett annat sÀtt. HÀr anvÀnder vi metoden för att garantera att t1
trÄden först startas och körs först, sedant2
trÄd, och först efter det kommer programmets huvudtrÄd att fortsÀtta. GÄ vidare. I riktiga program hittar du ofta situationer dÄ du behöver avbryta exekveringen av en trÄd. VÄr trÄd Àr till exempel igÄng, men den vÀntar pÄ en viss hÀndelse eller tillstÄnd. Om det intrÀffar stannar trÄden. Det skulle förmodligen vara vettigt om det fanns nÄgon form av stop()
metod. Men det Àr inte sÄ enkelt. En gÄng i tiden hade Java faktiskt en Thread.stop()
metod och tillÀt en trÄd att avbrytas. Men det togs senare bort frÄn Java-biblioteket. Du kan hitta den i Oracle-dokumentationen och se att den Àr markerad som utfasad. Varför? För det stoppade bara trÄden utan att göra nÄgot annat. TrÄden kan till exempel vara att arbeta med data och Àndra nÄgot. Sedan, mitt i arbetet, avbröts den plötsligt och utan ceremonier av stop()
metoden. Utan en ordentlig avstĂ€ngning, inte heller frigörande av resurser, inte ens felhantering â det fanns inget av detta. För att överdriva nĂ„got sĂ„ stop()
förstörde metoden helt enkelt allt pÄ sitt sÀtt. Det var som att dra strömsladden ur uttaget för att stÀnga av datorn. Ja, du kan fÄ önskat resultat. Men alla vet att efter ett par veckor kommer datorn inte att tacka dig för att du behandlar den pÄ det sÀttet. Det Àr dÀrför logiken för att avbryta trÄdar Àndrades i Java och anvÀnder nu en speciell interrupt()
metod.
Metoden Thread.interrupt()
Vad hÀnder ominterrupt()
metoden anropas i en trÄd? Det finns 2 möjligheter:
- Om objektet var i vÀntelÀge, till exempel pÄ grund av metoderna
join
ellersleep
, avbryts vÀntan och programmet kommer att kasta enInterruptedException
. - Om trÄden var i ett fungerande tillstÄnd
interrupted
kommer den booleska flaggan att sÀttas pÄ objektet.
Thread
klassen har boolean isInterrupted()
metoden. LÄt oss ÄtergÄ till klockexemplet som fanns pÄ en lektion i grundkursen. För enkelhetens skull har vi förenklat det nÄgot:
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 det hÀr fallet startas klockan och börjar ticka varje sekund. I den 10:e sekunden avbryter vi klockans trÄd. Som du redan vet, om trÄden som vi försöker avbryta Àr i en av de vÀntande tillstÄnden, Àr resultatet en InterruptedException
. Detta Àr ett kontrollerat undantag, sÄ vi kan enkelt fÄnga det och köra vÄr logik för att avsluta programmet. Och det Àr precis vad vi gjorde. HÀr Àr vÄrt resultat: Tick Tick Tick Tick Tick Tick Tick Tick Tick TrÄden avbröts Detta avslutar vÄr introduktion till Thread
klassens viktigaste metoder. Lycka till!
GO TO FULL VERSION