3.1 Actief object

Een actief object is een ontwerppatroon dat de uitvoeringsthread van een methode scheidt van de thread waarin deze werd aangeroepen. Het doel van dit patroon is om parallelle uitvoering te bieden met behulp van asynchrone methodeaanroepen en een planner voor het verwerken van verzoeken.

Vereenvoudigde versie:

actief voorwerp

Klassieke variant:

Actief voorwerp 2

Deze sjabloon heeft zes elementen:

  • Een proxy-object dat een interface biedt voor de openbare methoden van de client.
  • Een interface die toegangsmethoden voor het actieve object definieert.
  • Lijst met inkomende verzoeken van klanten.
  • Een planner die de volgorde bepaalt waarin query's moeten worden uitgevoerd.
  • Implementatie van actieve objectmethoden.
  • Een terugbelprocedure of een variabele voor de client om een ​​resultaat te ontvangen.

3.2 slot

Het Lock-patroon is een synchronisatiemechanisme dat exclusieve toegang tot een gedeelde bron tussen meerdere threads mogelijk maakt. Vergrendelingen zijn een manier om beleid voor gelijktijdigheidscontrole af te dwingen.

In feite wordt een zachte vergrendeling gebruikt, in de veronderstelling dat elke thread probeert "de vergrendeling te verkrijgen" voordat toegang wordt verkregen tot de overeenkomstige gedeelde bron.

Sommige systemen bieden echter een verplicht vergrendelingsmechanisme waarbij een ongeautoriseerde toegangspoging tot een vergrendelde bron wordt afgebroken door een uitzondering te genereren op de thread die probeerde toegang te krijgen.

Een semafoor is het eenvoudigste type slot. Bij datatoegang wordt geen onderscheid gemaakt tussen toegangsmodi: gedeeld (alleen-lezen) of exclusief (lezen-schrijven). In gedeelde modus kunnen meerdere threads een vergrendeling aanvragen om toegang te krijgen tot gegevens in alleen-lezen modus. De exclusieve toegangsmodus wordt ook gebruikt in de update- en verwijderalgoritmen.

slot patroon

De soorten sloten onderscheiden zich door de strategie om de voortzetting van de uitvoering van de thread te blokkeren. In de meeste implementaties voorkomt een verzoek om een ​​vergrendeling dat de thread wordt uitgevoerd totdat de vergrendelde bron beschikbaar is.

Een spinlock is een slot dat in een lus wacht totdat toegang wordt verleend. Een dergelijke vergrendeling is zeer efficiënt als een thread een korte tijd op een vergrendeling wacht, waardoor overmatige herschikking van threads wordt vermeden. De kosten van het wachten op toegang zullen aanzienlijk zijn als een van de threads het slot lange tijd vasthoudt.

sluitpatroon 2

Om het vergrendelingsmechanisme effectief te implementeren, is ondersteuning op hardwareniveau vereist. Hardware-ondersteuning kan worden geïmplementeerd als een of meer atomaire bewerkingen, zoals "testen en instellen", "ophalen en toevoegen" of "vergelijken en verwisselen". Met dergelijke instructies kunt u zonder onderbreking controleren of het slot vrij is, en zo ja, het slot aanschaffen.

3.3 Monitoren

Het monitorpatroon is een procesinteractie- en synchronisatiemechanisme op hoog niveau dat toegang biedt tot gedeelde bronnen. Een benadering voor het synchroniseren van twee of meer computertaken met behulp van een gemeenschappelijke bron, meestal hardware of een reeks variabelen.

Bij op een monitor gebaseerde multitasking voegt de compiler of interpreter op transparante wijze vergrendelings- en ontgrendelingscode in correct geformatteerde routines in, transparant voor de programmeur, waardoor de programmeur niet expliciet synchronisatieprimitieven hoeft aan te roepen.

De monitor bestaat uit:

  • een reeks procedures die interageren met een gedeelde bron
  • mutex
  • variabelen die aan deze bron zijn gekoppeld
  • een invariant die voorwaarden definieert om een ​​raceconditie te vermijden

De monitorprocedure verkrijgt de mutex voordat met het werk wordt begonnen en houdt deze vast totdat de procedure wordt beëindigd of totdat op een bepaalde voorwaarde wordt gewacht. Als elke procedure garandeert dat de invariant waar is voordat de mutex wordt vrijgegeven, kan geen enkele taak de hulpbron verwerven in een raceconditie.

Dit is hoe de gesynchroniseerde operator in Java werkt met de methoden wait()en notify().

3.4 Dubbelcheck vergrendeling

Dubbel gecontroleerde vergrendeling is een parallel ontwerppatroon dat bedoeld is om de overhead van het verkrijgen van een vergrendeling te verminderen.

Eerst wordt de blokkerende voorwaarde gecontroleerd zonder enige synchronisatie. Een thread probeert alleen een slot te verkrijgen als het resultaat van de controle aangeeft dat het slot moet worden verkregen.

//Double-Checked Locking
public final class Singleton {
private static Singleton instance; //Don't forget volatile modifier

public static Singleton getInstance() {
     if (instance == null) {                //Read

         synchronized (Singleton.class) {    //
             if (instance == null) {         //Read Write
                 instance = new Singleton(); //
             }
         }
     }
 }

Hoe maak je een singleton-object in een thread-veilige omgeving?

public static Singleton getInstance() {
   if (instance == null)
    instance = new Singleton();
}

Als u een Singleton-object maakt uit verschillende threads, kan er een situatie ontstaan ​​waarin meerdere objecten tegelijkertijd worden gemaakt, en dit is onaanvaardbaar. Daarom is het redelijk om het maken van het object in een gesynchroniseerde instructie te verpakken.

public static Singleton getInstance() {
    synchronized (Singleton.class) {
        if (instance == null)
        instance = new Singleton();
    }
}

Deze aanpak zal werken, maar heeft een klein nadeel. Nadat het object is gemaakt, wordt elke keer dat u het in de toekomst probeert te krijgen, een controle uitgevoerd in het gesynchroniseerde blok, wat betekent dat de huidige thread en alles wat daarmee verband houdt, wordt vergrendeld. Dus deze code kan een beetje worden geoptimaliseerd:

public static Singleton getInstance() {
     if (instance != null)
        return instance;

    synchronized (Singleton.class) {
        if (instance == null)
        instance = new Singleton();
    }
}

Op sommige talen en/of op sommige machines is het niet mogelijk om dit patroon veilig te implementeren. Daarom wordt het soms een anti-patroon genoemd. Dergelijke functies hebben geleid tot het verschijnen van de strikte volgorderelatie "gebeurt vóór" in het Java-geheugenmodel en het C ++-geheugenmodel.

Het wordt meestal gebruikt om de overhead te verminderen van het implementeren van luie initialisatie in multi-threaded programma's, zoals het Singleton-ontwerppatroon. Bij luie initialisatie van een variabele wordt de initialisatie uitgesteld totdat de waarde van de variabele nodig is voor de berekening.

3.5 Planner

De Scheduler is een parallel ontwerppatroon dat een mechanisme biedt voor het implementeren van een planningsbeleid, maar onafhankelijk is van een bepaald beleid. Bepaalt de volgorde waarin threads sequentiële code moeten uitvoeren, met behulp van een object dat expliciet de volgorde van wachtende threads specificeert.