Sobes.tech
Middle

Čo je blok synchronized v Jave a aké problémy môžu pri jeho používaní nastať?

sobes.tech AI

Odpoveď od AI

Blok synchronized v Jave sa slúži na zabezpečenie synchronizácie prístupu ku spoločnému zdroju medzi viacerými vláknami. To zaručuje, že iba jedno vlákno môže vykonávať kód vo vnútri bloku v danom čase.

Struktúra bloku synchronized:

synchronized (monitorovy_objekt) {
    // Kritická sekcia
    // Tu sa vykonávajú operácie so spoločným zdrojom
}
  • monitorovy_objekt: akýkoľvek objekt, ktorý slúži ako monitor (zámok). Vlákna, ktoré sa pokúsia vstúpiť do synchronized bloku s rovnakým objektom, budú zablokované, kým aktuálne vlákno ne opustí blok.

Problémy, ktoré môžu nastať pri používaní synchronized:

  • Vražedný zámok (Deadlock): Dve alebo viac vlákien čakajú na uvoľnenie zdroja, ktorý je obsadený iným vláknom, čo vedie k zablokovaniu programu. To sa môže stať, ak vlákna získavajú zámky v rôznom poradí.
  • Zníženie výkonu: Synchronizácia blokuje vykonávanie iných vlákien, ktoré čakajú na prístup k monitoru, čo môže spomaliť prácu paralelných aplikácií.
  • Neaplikovateľnosť v niektorých scenároch: synchronized zabezpečuje exkluzívny prístup. V niektorých prípadoch môže byť potrebné flexibilnejšie riadenie prístupu (napríklad čítanie viacerými vláknami súčasne, zápis v jednom vlákne).
  • Zložitosť ladenia: Problémy so synchronizáciou môžu byť nejasné a ťažko reprodukovateľné a odhaľovateľné.

Príklad vzájomného zámku:

class Resource {
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void method1(Resource other) {
        synchronized (lock1) {
            try {
                Thread.sleep(100); // Simulácia práce
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " získal lock1");
            synchronized (other.lock2) {
                System.out.println(Thread.currentThread().getName() + " získal lock2 iného");
            }
        }
    }

    public void method2(Resource other) {
        synchronized (lock2) {
             try {
                Thread.sleep(100); // Simulácia práce
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " získal lock2");
            synchronized (other.lock1) {
                System.out.println(Thread.currentThread().getName() + " získal lock1 iného");
            }
        }
    }
}

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();
    }
}

V tomto príklade sa Thread-1 snaží získať lock1 r1 a potom lock2 r2. Thread-2 sa snaží získať lock2 r2 a potom lock1 r1. Ak ich získajú súčasne, dôjde k vzájomnému zámku.