Syncronisatie in Java

Wat is Syncronisatie in Java?

In Java, synchronisatie verwijst naar de mogelijkheid om de toegang van meerdere threads tot een gedeelde resource te beheren. Het is een ideale optie als we slechts één thread toegang willen geven tot de gedeelde resource.

Deze benadering van uitvoering wordt gewoonlijk `asynchrone` programmering genoemd. Er zijn ook threads op deze processors, wat lichtgewicht processen zijn die instructies gelijktijdig kunnen uitvoeren.

Types van Synckroning

Er zijn twee soorten synchronisatiemethoden in Java:

1) Proces synchronisatie

2) Synchronisatie van threads.

Laten we Thread en bestuderen Proces synchronisatie in detail.

Proces synchronisatie: Het beheert synchronisatie tussen programma's. Bijvoorbeeld programma's zoals `Microsoft Word` en `Acrobat reader` worden als afzonderlijke processen uitgevoerd.

Threadsynchronisatie: De gelijktijdige uitvoering van de kritieke bron door twee of meer Threads wordt Thread genoemd Syncronisatie. U kunt verder worden gegroepeerd op het gebied van wederzijds exclusieve communicatie en communicatie tussen threads.

Wat is Lock-in Java?

Opsluiten Java is gebouwd rond een interne entiteit die bekend staat als een monitor of het slot. Aan al het object is een slot gekoppeld. De thread die consistente toegang tot de velden van een object nodig heeft, moet dus de vergrendeling van het object verkrijgen voordat hij er toegang toe krijgt, en geeft de vergrendeling vrij wanneer het werk is gedaan. Dit zorgt ervoor dat slechts één thread tegelijk toegang heeft tot de gedeelde gegevens.

Multithreaded programma met synchronisatie

Een multithreaded programma is een methode of blok dat beschermd is tegen interferentie van andere threads die dezelfde resource delen, zoals aangegeven met het trefwoord `synchronized`.

Gebruik van de gesynchroniseerde methode

Elke methode die als gesynchroniseerd is gedeclareerd, staat bekend als een gesynchroniseerde methode. Het wordt ook gebruikt om een ​​object te vergrendelen voor een gedeelde resource. Dus wanneer een thread een gesynchroniseerde methode aanroept, neemt het automatisch bezit van de vergrendeling voor dat object en geeft het deze vrij wanneer het zijn taak heeft voltooid.

Opmerking: Het trefwoord synchroon kan niet werken met klassen en variabelen. Alleen methoden en blokken kunnen worden gebruikt met het trefwoord.

Waarom de Syncgeroniseerde methode?

  • Het wordt gebruikt voor het vergrendelen van een object voor gedeelde bronnen.
  • Het object krijgt de vergrendeling wanneer de gesynchroniseerde methode wordt aangeroepen.
  • De vergrendeling wordt pas vrijgegeven als de draad zijn functie heeft voltooid

Syntax:

Acess_modifiers synchronized return_type method_name (Method_Parameters) {
}
class MathService {
    synchronized void getSumOfArray(int[] numbers) {
     int sum = 0;

         for (int number : numbers) {
             System.out.println(Thread.currentThread()
                     .getName()
                     + " adds "
                     + sum + " to "
                     + number + " to get -> "
                     + (sum += number));

             try {
                 Thread.sleep(500);
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
         }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
    }
}

Verklaring van code:

Voer dit voorbeeld uit en zie dat thread `0` eerst de vergrendeling van het `mathService`-object ophaalt en deze vergrendeling exclusief gebruikt totdat de uitvoering ervan is voltooid. Thread `0` en `1` zijn in deze code niet doorschoten. De uitvoer is zoals hieronder weergegeven.

Output:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

Een gesynchroniseerd blok gebruiken

Laten we aannemen dat u niet de hele methode wilt synchroniseren. In plaats daarvan wilt u een paar regels code synchroniseren. Op dat moment is de Syncgechroniseerd blok hielp bij het synchroniseren van de geselecteerde Java code. SyncGesynchroniseerde methodevergrendelingen worden benaderd via de methode, terwijl gesynchroniseerde blokvergrendelingen worden benaderd via het object.

class MathService {
    void getSumOfArray(int[] numbers) {
        synchronized (this){
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
    }
}

Code Verklaring:

Wanneer u deze code uitvoert, zult u merken dat deze zonder enige interferentie werkt. In de gesynchroniseerde methode wordt de vergrendeling toegepast door de methode, maar in het gesynchroniseerde blok wordt de vergrendeling toegepast door het object. Zorg ervoor dat de uitvoer is zoals hieronder weergegeven.

Output:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

Toelichting code:

Wanneer u deze code uitvoert, zult u merken dat het zonder interferentie werkt, wat we verwachtten. In de synchronized methode wordt de lock toegepast door de methode, maar in de synchronized block methode wordt de lock toegepast door het object.

Statische synchronisatie gebruiken

In Java synchronisatie, als er meer dan één object is, kunnen twee threads de vergrendelingen verkrijgen en een gesynchroniseerd blok of blok binnengaan, met een aparte vergrendeling voor elk object. Om dit te voorkomen, kan statische synchronisatie worden gebruikt. SyncGehroniseerde trefwoorden zullen vóór statische methoden worden gebruikt.

Opmerking: Bij statische synchronisatie vindt de vergrendelingstoegang plaats op de klasse, niet op het object en de methode.

Code om het probleem van het vergrendelen van meerdere objecten aan te tonen

class MathService {
    synchronized void getSumOfArray(int[] numbers) {
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();
        MathService mathService1 = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));
        Thread threadThree = new Thread(() ->
                mathService1.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadFour = new Thread(() ->
                mathService1.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
        threadThree.start();
        threadFour.start();
    }
}

Toelichting code:

Wanneer we nog een exemplaar van de `MathService` maken, introduceren we interferentie in de threads, aangezien deze worden verweven met de twee objecten. Merk op dat thread '0' en thread '2' zijn verweven met de twee objecten, terwijl thread '1' en '3' zijn verweven met de twee objecten.

Output:

Thread-0 adds 0 to 10 to get -> 10
Thread-2 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-2 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-2 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-3 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-3 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63
Thread-3 adds 41 to 22 to get -> 63

Dezelfde code met behulp van een gesynchroniseerde statische methode

class MathService {
    synchronized static void getSumOfArray(int[] numbers) {
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();
        MathService mathService1 = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));
        Thread threadThree = new Thread(() ->
                mathService1.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadFour = new Thread(() ->
                mathService1.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
        threadThree.start();
        threadFour.start();
    }
}

Voer de bovenstaande code uit en merk op dat we nu threadinterferentie hebben geëlimineerd. De uitvoer van de code wordt hieronder weergegeven.

Output:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-3 adds 0 to 20 to get -> 20
Thread-3 adds 20 to 21 to get -> 41
Thread-3 adds 41 to 22 to get -> 63
Thread-2 adds 0 to 10 to get -> 10
Thread-2 adds 10 to 11 to get -> 21
Thread-2 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

Voordelen van het gebruik van synchronisatie

Dit zijn de voordelen van het werken met gelijktijdige toepassingen:

  • Het hoofddoel van synchronisatie in Java is om inconsistente gegevens te voorkomen door threadinterferentie te voorkomen.
  • Het gesynchroniseerde trefwoord in Java zorgt voor vergrendeling, waardoor wederzijds exclusieve toegang tot de gedeelde bron wordt gegarandeerd en datarace wordt voorkomen.
  • Het voorkomt ook dat de code-instructies opnieuw worden geordend door de compiler, wat een subtiel gelijktijdig probleem kan veroorzaken als we geen vluchtige of gesynchroniseerde trefwoorden gebruiken.
  • Synchronized trefwoord leest gegevens uit het hoofdgeheugen dan de cache en wanneer het de vergrendeling vrijgeeft.
  • Het verwijdert bovendien schrijfbewerkingen uit het hoofdgeheugen, waardoor inconsistente geheugenfouten worden geëlimineerd.

Nadelen van Syncronisatiemechanisme

Syncronisatie Mechanismen presteren slecht.

Bij voorbeeld

  • Stel dat er vijf processen zijn: A1, A2, A3, A4 en A5.
  • Ze wachten tot de gedeelde bronnen toegang krijgen tot één thread tegelijk.
  • Alle processen blijven wachten, dus de laatste in de wachtrij moet wachten totdat alle andere processen zijn voltooid.

Samenvatting

  • Syncronisatie verwijst naar de mogelijkheid om de toegang van meerdere threads tot een gedeelde bron te controleren.
  • Java heeft twee soorten synchronisatiemethoden: 1) Proces synchronisatie en 2) Synchronisatie van threads.
  • Opsluiten Java is gebouwd rond een interne entiteit die bekend staat als een monitor of het slot.
  • Een multithreaded programma is een methode of blok dat beschermd is tegen interferentie van andere threads die dezelfde bron delen, zoals aangegeven met het trefwoord `synchronized`.
  • Elke methode die als gesynchroniseerd wordt gedeclareerd, wordt een gesynchroniseerde methode genoemd.
  • In Javaworden gesynchroniseerde methodevergrendelingen benaderd op de methode, terwijl gesynchroniseerde blokvergrendelingen benaderd worden op het object.
  • Bij statische synchronisatie vindt de vergrendelingstoegang plaats op de klasse, niet op het object en de methode.
  • Het hoofddoel van synchronisatie in Java is om inconsistente gegevens te voorkomen door threadinterferentie te voorkomen.
  • Het grootste nadeel van deze methode is dat alle processen wachten, dus de laatste in de wachtrij moet wachten totdat alle andere processen zijn voltooid.