Miloš Němec, osobní stránka

 Novinky Literatura Hudba Cestování a turistika Věda a technika Ostatní 
Domů > Věda a technika

Java: Synchronizace kritických sekcí

Kritické sekce jsou úseky kódu, jejichž paralelní běh může způsobit problémy. Typicky se jedná o situaci, kdy více vláken pracuje nad stejnými daty.

Školní příklad takového kódu:

public class Point {

    private int[] xy = {0, 0};   

    public void printXy() {
        System.out.println(xy[0] + ", " + xy[1]);
    }

    public void setXy(int x, int y) {
        xy[0] = x;
        xy[1] = y;
    }
}

Pokud budou metody printXy() a setXy() volány z oddělených vláken, je jen otázkou času, kdy dojde k chybě.

Vlákna totiž ve skutečnosti nepracují paralelně, ale pouze pseudoparalelně. Zdánlivě paralelní běh je zajištěn jejich rychlým střídáním. A pokud dojde k předání řízení v okamžiku, kdy je zapsána pouze první položka pole xy, při následném volání printXy() bude vytištěna nesprávná hodnota.

Řešením je synchronizace kritických sekcí – kritické sekce pak nemohou probíhat paralelně, ale pouze sériově.

Java pro tyto účely poskytuje mechanismus monitorů, které lze aktivovat klíčovým slovem synchronized.

Vlákno získává monitor při vstupu do kritické sekce a uvolňuje jej při opuštění. Žádné jiné vlákno pak nemůže provést synchronizovanou sekci se stejným monitorem.

Synchronizované metody

synchronized public void printXy() {
    System.out.println(xy[0] + ", " + xy[1]);
}

synchronized public void setXy(int x, int y) {
     xy[0] = x;
     xy[1] = y;
}

Metody označené klíčovým slovem synchronized jsou v rámci instance nepřerušitelné. Proč v rámci instance? Protože monitor je vždy svázán s objektem. V případě synchronizovaných metod s instancí obalující třídy.

Vždy je třeba synchronizovat všechny kritické sekce. Použití monitoru v jedné kritické sekci nezabrání paralelnímu vykonání jiné kritické sekce bez monitoru.

Často se lze setkat se zcela mylným názorem, že synchronizovaná metoda je nepřerušitelná. Není to pravda, současně dokonce může běžet i více kritických sekcí, které ale nesdílejí stejný monitor.

Synchronizované bloky

Výše uvedený zápis synchronizace metod je ekvivalentní následujícímu:

public void printXy() {
    synchronized (this) {
        System.out.println(xy[0] + ", " + xy[1]);
    }
}


public void setXy(int x, int y) {
    synchronized (this) {
         xy[0] = x;
         xy[1] = y;
    }
}

Pokud není žádoucí synchronizovat celou metodu, lze synchronizovat pouze její část - synchronizovaný blok. Tento postup využijeme především tehdy, když chceme monitor svázat s jiným objektem, než je instance třídy s deklarovanými metodami.

public class Point {

    private int[] xy = {0, 0};   
    private final Object sync = new Object();

    public void printXy() {
        synchronized (sync) {
            System.out.println(xy[0] + ", " + xy[1]);
        }
    }

    public void setXy(int x, int y) {
        synchronized (sync) {
            xy[0] = x;
            xy[1] = y;
        }
    }
}

Objekt sync je deklarován jako finální. Monitor je svázán s instancí, změna instance by tedy zapříčinila zneplatnění monitoru. Pokud se pokusíte použít nefinální objekt, překladač Vás upozorní varováním synchronization on non-final field.

Kdy použít synchronizaci přes jiný objekt než je instance třídy s deklarovanými metodami? Především tam kde může běžet více kritických sekcí nad různými monitory.

Sociální záložky (?): linkuj.czfacebook.comtopclanky.cz


Tento článek si od 26. 6. 2010 přečetlo 132 čtenářů.



Diskuze:

V dizkuzi zatím nejsou žádné příspěvky.
Než přidáte svůj příspěvek, mějte prosím na zřeteli, že budou smazány:
  • všechy vulgarity,
  • všechny příspěvky netýkající se tématu.
© 2003-2010 Miloš Němec. Všechna práva vyhrazena. Kontakt. Reklama. RSS 2.0 kanál (články) RSS