Sobes.tech
Middle

Mis on synchronized plokk Java-s ja millised probleemid võivad selle kasutamisel tekkida?

sobes.tech AI

Vastus AI-lt

Java synchronized blokk i izmanto, lai nodrošinātu piekļuves sinhronizāciju kopīgam resursam starp vairākiem pavedieniem. Tas garantē, ka tikai viens pavediens var izpildīt kodu blokā vienlaikus.

Synchronized bloka struktūra:

synchronized (monitora_objekts) {
    // Kritiskā sekcija
    // Šeit tiek veiktas operācijas ar kopīgo resursu
}
  • monitora_objekts: jebkurš objekts, kas darbojas kā monitors (lock). Pavedieni, kas mēģina ieiet synchronized blokā ar to pašu monitora objektu, tiks bloķēti līdz brīdim, kad pašreizējais pavediens izies no bloka.

Iespējamās problēmas, izmantojot synchronized:

  • Aizsargājoša bloķēšana (Deadlock): Divi vai vairāki pavedieni gaida resursa atbrīvošanu, kas ir aizņemts ar citu pavedienu, kas noved pie programmas iesaldēšanas. Tas var notikt, ja pavedieni mēģina iegūt bloķējumus dažādā secībā.
  • Veiktspējas samazināšanās: Synchronized bloķē citu pavedienu izpildi, kas gaida piekļuvi monitoram, kas var palēnināt paralēlo lietojumprogrammu darbību.
  • Neatbilstošība dažiem scenārijiem: synchronized nodrošina ekskluzīvu piekļuvi. Dažos gadījumos var būt nepieciešama elastīgāka piekļuves pārvaldība (piemēram, lasīšana ar vairākiem pavedieniem vienlaikus, rakstīšana vienā pavedienā).
  • Grūti diagnosticēt: Sinhronizācijas problēmas var būt neizskaidrojamas un grūti reproducējamas un novēršamas.

Vairāk par aizsargājošo bloķēšanu:

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

    public void metode1(Resursi cits) {
        synchronized (lock1) {
            try {
                Thread.sleep(100); // Imitācija darba
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " ieguva lock1");
            synchronized (cits.lock2) {
                System.out.println(Thread.currentThread().getName() + " ieguva cita lock2");
            }
        }
    }

    public void metode2(Resursi cits) {
        synchronized (lock2) {
             try {
                Thread.sleep(100); // Imitācija darba
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " ieguva lock2");
            synchronized (cits.lock1) {
                System.out.println(Thread.currentThread().getName() + " ieguva cita lock1");
            }
        }
    }
}

public class DeadlockExample {
    public static void main(String[] args) {
        Resursi r1 = new Resursi();
        Resursi r2 = new Resursi();

        new Thread(() -> r1.metode1(r2), "Pavedien-1").start();
        new Thread(() -> r2.metode2(r1), "Pavedien-2").start();
    }
}

Šajā piemērā Pavedien-1 mēģina iegūt lock1 r1 un pēc tam lock2 r2. Pavediens-2 mēģina iegūt lock2 r2 un pēc tam lock1 r1. Ja viņi iegūst pirmās bloķēšanas vienlaikus, rodas aizsargājoša bloķēšana.