Middle
Mi az a synchronized blokk Java-ban, és milyen problémák merülhetnek fel a használata során?
sobes.tech MI
Válasz az MI-től
A Java synchronized blokkja a közös erőforrásokhoz való hozzáférés szinkronizálására szolgál több szál között. Ez garantálja, hogy csak egy szál hajthat végre kódot a blokkban egy adott időben.
A synchronized blokk szerkezete:
synchronized (objektum_monitor) {
// Kritikus szekció
// Itt történnek a közös erőforrással kapcsolatos műveletek
}
objektum_monitor: bármilyen objektum, amely monitor (zár) szerepét tölti be. Azok a szálak, amelyek ugyanazzal az objektummal próbálnak belépni asynchronizedblokkba, blokkolva lesznek, amíg a jelenlegi szál ki nem lép a blokkból.
A synchronized használata során felmerülő problémák:
- Halálos zárlat (Deadlock): Két vagy több szál vár egy erőforrás felszabadítására, amelyet egy másik szál foglal el, ez a program lefagyásához vezet. Ez akkor fordulhat elő, ha a szálak különböző sorrendben próbálják megszerezni a zárolásokat.
- Teljesítménycsökkenés: A szinkronizáció blokkolja a többi szál végrehajtását, amelyek a monitorhoz való hozzáférést várják, ez lassíthatja a párhuzamos alkalmazásokat.
- Nem alkalmazható bizonyos szcenáriókban: A
synchronizedkizárólagos hozzáférést biztosít. Bizonyos esetekben rugalmasabb hozzáférés-vezérlésre lehet szükség (pl. több szál olvashat egyszerre, de csak egy írhat). - Hibakeresés nehézségei: A szinkronizációs problémák nem mindig nyilvánvalóak, és nehéz reprodukálni vagy hibakeresni őket.
Példa a halálos zárlatra:
class Resource {
private Object lock1 = new Object();
private Object lock2 = new Object();
public void method1(Resource other) {
synchronized (lock1) {
try {
Thread.sleep(100); // Munka szimulálása
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " megszerezte a lock1-et");
synchronized (other.lock2) {
System.out.println(Thread.currentThread().getName() + " megszerezte a másik lock2-ét");
}
}
}
public void method2(Resource other) {
synchronized (lock2) {
try {
Thread.sleep(100); // Munka szimulálása
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " megszerezte a lock2-t");
synchronized (other.lock1) {
System.out.println(Thread.currentThread().getName() + " megszerezte a másik lock1-et");
}
}
}
}
public class DeadlockExample {
public static void main(String[] args) {
Resource r1 = new Resource();
Resource r2 = new Resource();
new Thread(() -> r1.method1(r2), "Thread-1").start();
new Thread(() -> r2.method2(r1), "Thread-2").start();
}
}
Ebben a példában az Thread-1 megpróbálja megszerezni az lock1-et r1-en, majd az lock2-t r2-n. A Thread-2 megpróbálja megszerezni az lock2-t r2-n, majd az lock1-t r1-en. Ha mindkettő egyszerre szerzi meg az első zárolásokat, akkor halálos zárlat alakul ki.