Szia! Ma továbbra is a többszálú feldolgozásról fogunk beszélni. Vizsgáljuk meg a Thread osztályt és néhány metódusát. Amikor korábban tanulmányoztuk az osztálymetódusokat, általában csak ezt írtuk: <metódus neve> -> <mit csinál a metódus>.
Ez nem fog működni
Idézzük fel a példát az előző leckéből:
A
A

Thread
's metódusaival :) Összetettebb logikájuk van, amit néhány példa nélkül nem fogsz kitalálni.
A Thread.start() metódus
Kezdjük önmagunk ismétlésével. Amint valószínűleg emlékszel, létrehozhat egy szálat úgy, hogy az osztály örökli azThread
osztályt, és felülírja a run()
metódust. De persze nem indul el magától. Ehhez hívjuk objektumunk start()
metódusát. 
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();
}
}
}
Megjegyzés: A szál indításáhozstart()
a metódus helyett a speciális metódustrun()
! Ez könnyen elkövethető hiba, különösen akkor, ha először kezdi el a többszálú tanulást. Példánkban, harun()
10-szer hívja meg a metódust a helyettstart()
, a következőt kapja:
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.run();
}
}
}
Tekintse meg programunk eredményét: Szál végrehajtva: Thread-0 Szál végrehajtva: Thread-1 Szál végrehajtva: Thread-2 Szál végrehajtva: Thread-3 Szál végrehajtva: Thread-4 Szál végrehajtva: Thread-5 Szál végrehajtva: Thread-6 Szál végrehajtva: Thread-7 Szál végrehajtva: Thread-8 Szál végrehajtva: Thread-9 Nézd meg a kimenet sorrendjét: Minden tökéletes rendben történik. Furcsa, mi? Nem szoktuk ezt meg, mert már tudjuk, hogy a szálak indításának és végrehajtásának sorrendjét az operációs rendszerünkön belüli felsőbbrendű intellektus határozza meg: a szálütemező. Talán csak szerencsénk volt? Persze ez nem a szerencsén múlik. Ezt úgy ellenőrizheti, hogy még néhányszor futtatja a programot. A probléma az, hogy hívja arun()
metódusnak közvetlenül semmi köze a többszálú kezeléshez. Ebben az esetben a program a fő szálon fut, ugyanazon a szálon, amelyik a main()
metódust is végrehajtja. Egyszerűen egymás után 10 sort nyomtat a konzolra, és kész. 10 szál még nem indult el. Tehát ne feledje ezt a jövőben, és folyamatosan ellenőrizze magát. Ha azt szeretné, hogy a run()
metódus meghívásra kerüljön, hívja a start()
. Menjünk tovább.
A Thread.sleep() metódus
Az aktuális szál végrehajtásának egy időre történő felfüggesztéséhez a módszert használjuksleep()
. 
sleep()
metódus néhány ezredmásodpercet vesz igénybe argumentumként, amely azt jelzi, hogy mennyi ideig kell a szálat aludni.
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");
}
}
Konzol kimenet: - Meddig aludtam? - 3 másodperc Megjegyzés: a sleep()
metódus statikus: elalszik az aktuális szálat. Vagyis a jelenleg kivégzés alatt álló. Itt van még egy fontos pont: az alvó szál megszakítható. Ebben az esetben a program egy InterruptedException
. Az alábbiakban egy példát veszünk figyelembe. Amúgy mi történik, miután felébred a cérna? Ott folytatódik a végrehajtás, ahol abbahagyta? Nem. Miután egy szál felébred, azaz az argumentumként eltelt idő lejárt Thread.sleep()
, átvált futtathatóváállapot. Ez azonban nem jelenti azt, hogy a szálütemező futtatni fogja. Lehetséges, hogy előnyben részesít egy másik, nem alvó szálat, és hagyja, hogy frissen felébredt szálunk egy kicsit később folytassa a munkáját. Ne feledje: az ébredés nem jelenti azt, hogy azonnal folytatni kell a munkát!
A Thread.join() metódus

join()
metódus felfüggeszti az aktuális szál végrehajtását, amíg egy másik szál be nem fejeződik. Ha van 2 szálunk, t1
és t2
, és írunk
t1.join()
akkor t2
nem indul el, amíg be t1
nem fejezi a munkáját. A join()
módszer használható a szálak végrehajtási sorrendjének garantálására. Nézzük meg, hogyan join()
működik a módszer a következő példában:
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.");
}
}
Létrehoztunk egy egyszerű ThreadExample
osztályt. Feladata, hogy üzenetet jelenítsen meg, hogy elindult a szál, elalszik 5 másodpercre, majd végül jelenti a munka befejezését. Szelet torta. A fő logika az osztályban van Main
. Nézze meg a megjegyzéseket: a join()
metódus segítségével sikeresen kezeljük a szálak végrehajtási sorrendjét. Ha emlékszel, hogyan indítottuk el ezt a témát, a végrehajtási sorrendet a szálütemező kezeli. A szálakat saját belátása szerint futtatja: minden alkalommal más módon. Itt azt a módszert használjuk, hogy garantáljuk, hogy t1
először a szál induljon el és hajtsa végre először, majd at2
szál, és csak ezután folytatódik a program főszála. Továbblépni. Valódi programokban gyakran előfordul olyan helyzet, amikor meg kell szakítania egy szál végrehajtását. Például a szálunk fut, de egy bizonyos eseményre vagy feltételre vár. Ha ez megtörténik, a szál leáll. Valószínűleg lenne értelme, ha lenne valamilyen stop()
módszer. De ez nem ilyen egyszerű. Valaha a Java-nak volt egy Thread.stop()
metódusa, és lehetővé tette egy szál megszakítását. Később azonban eltávolították a Java könyvtárból. Megtalálhatja az Oracle dokumentációjában, és láthatja, hogy elavultként van megjelölve. Miért? Mert egyszerűen leállította a szálat anélkül, hogy bármi mást csinált volna. Például előfordulhat, hogy a szál adatokkal dolgozik, és megváltoztat valamit. Aztán munkája kellős közepén hirtelen és szertartásmentesen megszakította a stop()
módszer. Megfelelő leállítás, erőforrás-felszabadítás, még hibakezelés nélkül sem volt semmi. Kissé túlzásképpen a stop()
módszer egyszerűen mindent elpusztított az útjában. Olyan volt, mintha kihúzta volna a tápkábelt a konnektorból, hogy kikapcsolja a számítógépet. Igen, elérheti a kívánt eredményt. De mindenki tudja, hogy néhány hét múlva a számítógép nem fogja megköszönni, hogy így bánik vele. Ezért változott meg a szálak megszakításának logikája a Java-ban, és most egy speciális interrupt()
módszert használ.
A Thread.interrupt() metódus
Mi történik, ha ainterrupt()
metódust egy szálon hívják meg? 2 lehetőség van:
join
Ha az objektum várakozó állapotban volt például a vagy metódusok miattsleep
, akkor a várakozás megszakad, és a program egy -et dobInterruptedException
.- Ha a szál működő állapotban volt, akkor a logikai
interrupted
jelző kerül az objektumra.
Thread
van az osztályban a boolean isInterrupted()
módszer. Térjünk vissza az órapéldához, amely az alaptanfolyam egyik leckében volt. A kényelem kedvéért kissé leegyszerűsítettük:
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");
}
}
}
Ebben az esetben az óra elindul, és másodpercenként ketyegni kezd. A 10. másodpercben megszakítjuk az óra menetét. Amint azt már tudja, ha a megszakítani próbált szál valamelyik várakozási állapotban van, az eredmény egy InterruptedException
. Ez egy ellenőrzött kivétel, így könnyen elkaphatjuk, és végrehajthatjuk a logikánkat a program befejezéséhez. És csak ezt tettük. Íme az eredményünk: Tick Tick Tick Tcik Tick Tick Tick Tick A szál megszakadt Ezzel az Thread
osztály legfontosabb metódusaival kapcsolatos bemutatkozásunkat zárjuk. Sok szerencsét!
GO TO FULL VERSION