CodeGym/Java Course/Modulo 3/Pattern multithread

Pattern multithread

Disponibile

3.1 Oggetto attivo

Un oggetto Active è un modello di progettazione che separa il thread di esecuzione di un metodo dal thread in cui è stato chiamato. Lo scopo di questo modello è fornire l'esecuzione parallela usando chiamate di metodo asincrone e uno scheduler di elaborazione delle richieste.

Versione semplificata:

oggetto attivo

Variante classica:

Oggetto attivo 2

Questo modello ha sei elementi:

  • Un oggetto proxy che fornisce un'interfaccia ai metodi pubblici del client.
  • Un'interfaccia che definisce i metodi di accesso per l'oggetto attivo.
  • Elenco delle richieste in arrivo dai clienti.
  • Uno scheduler che determina l'ordine in cui devono essere eseguite le query.
  • Implementazione di metodi oggetto attivi.
  • Una procedura di callback o una variabile per il client per ricevere un risultato.

3.2 blocco

Il modello di blocco è un meccanismo di sincronizzazione che consente l'accesso esclusivo a una risorsa condivisa tra più thread. I blocchi sono un modo per applicare i criteri di controllo della concorrenza.

Fondamentalmente viene utilizzato un soft lock, con l'ipotesi che ogni thread tenti di “acquisire il lock” prima di accedere alla corrispondente risorsa condivisa.

Tuttavia, alcuni sistemi forniscono un meccanismo di blocco obbligatorio in base al quale un tentativo di accesso non autorizzato a una risorsa bloccata verrà interrotto generando un'eccezione sul thread che ha tentato di ottenere l'accesso.

Un semaforo è il tipo più semplice di blocco. In termini di accesso ai dati non viene fatta distinzione tra modalità di accesso: condiviso (sola lettura) o esclusivo (lettura-scrittura). In modalità condivisa, più thread possono richiedere un blocco per accedere ai dati in modalità di sola lettura. La modalità di accesso esclusivo viene utilizzata anche negli algoritmi di aggiornamento ed eliminazione.

modello di blocco

I tipi di blocchi si distinguono per la strategia di blocco della continuazione dell'esecuzione del thread. Nella maggior parte delle implementazioni, una richiesta di blocco impedisce al thread di continuare l'esecuzione fino a quando la risorsa bloccata non è disponibile.

Uno spinlock è un blocco che attende in un ciclo finché non viene concesso l'accesso. Tale blocco è molto efficiente se un thread attende un blocco per un breve periodo di tempo, evitando così un'eccessiva riprogrammazione dei thread. Il costo dell'attesa per l'accesso sarà significativo se uno dei thread mantiene il blocco per lungo tempo.

modello di blocco 2

Per implementare efficacemente il meccanismo di blocco, è necessario il supporto a livello hardware. Il supporto hardware può essere implementato come una o più operazioni atomiche come "test-and-set", "fetch-and-add" o "compare-and-swap". Tali istruzioni consentono di verificare senza interruzioni che il blocco sia libero e, in tal caso, acquisire il blocco.

3.3 Monitorare

Il modello Monitor è un meccanismo di interazione e sincronizzazione di processo di alto livello che fornisce l'accesso alle risorse condivise. Un approccio alla sincronizzazione di due o più attività del computer utilizzando una risorsa comune, in genere hardware o un insieme di variabili.

Nel multitasking basato su monitor, il compilatore o l'interprete inserisce in modo trasparente il codice di blocco e sblocco in routine formattate in modo appropriato, in modo trasparente per il programmatore, salvando il programmatore dal chiamare esplicitamente le primitive di sincronizzazione.

Il monitor è composto da:

  • un insieme di procedure che interagiscono con una risorsa condivisa
  • mutex
  • variabili associate a questa risorsa
  • un invariante che definisce le condizioni per evitare una race condition

La procedura monitor acquisisce il mutex prima di iniziare il lavoro e lo conserva fino a quando la procedura non esce o fino a quando non si attende una determinata condizione. Se ogni procedura garantisce che l'invariante è vero prima di rilasciare il mutex, nessuna attività può acquisire la risorsa in una race condition.

Ecco come funziona l' operatore sincronizzato in Java con i metodi wait()e notify().

3.4 Chiusura a doppio controllo

Il blocco a doppio controllo è un modello di progettazione parallelo inteso a ridurre il sovraccarico per ottenere un blocco.

Innanzitutto, la condizione di blocco viene verificata senza alcuna sincronizzazione. Un thread tenta di acquisire un blocco solo se il risultato del controllo indica che deve acquisire il blocco.

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

Come creare un oggetto singleton in un ambiente thread-safe?

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

Se crei un oggetto Singleton da thread diversi, potrebbe esserci una situazione in cui vengono creati più oggetti contemporaneamente e questo è inaccettabile. Pertanto, è ragionevole racchiudere la creazione dell'oggetto in un'istruzione sincronizzata.

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

Questo approccio funzionerà, ma ha un piccolo svantaggio. Dopo che l'oggetto è stato creato, ogni volta che proverai a ottenerlo in futuro, verrà eseguito un controllo nel blocco sincronizzato, il che significa che il thread corrente e tutto ciò che è connesso ad esso saranno bloccati. Quindi questo codice può essere ottimizzato un po':

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

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

Su alcuni linguaggi e/o su alcune macchine non è possibile implementare in sicurezza questo pattern. Pertanto, a volte viene chiamato anti-pattern. Tali caratteristiche hanno portato alla comparsa della stretta relazione di ordine "accade prima" nel modello di memoria Java e nel modello di memoria C++.

Viene in genere utilizzato per ridurre l'overhead dell'implementazione dell'inizializzazione lazy in programmi multithread, come il modello di progettazione Singleton. Nell'inizializzazione pigra di una variabile, l'inizializzazione viene posticipata finché il valore della variabile non è necessario nel calcolo.

3.5 Agenda

Lo Scheduler è un modello di progettazione parallelo che fornisce un meccanismo per implementare una politica di pianificazione, ma è indipendente da qualsiasi politica particolare. Controlla l'ordine in cui i thread devono eseguire il codice sequenziale, usando un oggetto che specifica in modo esplicito la sequenza dei thread in attesa.

1
Compito
Modulo 3,  livello 17lezione 2
Bloccato
Trust, but Verify
task4123
Commenti
  • Popolari
  • Nuovi
  • Vecchi
Devi avere effettuato l'accesso per lasciare un commento
Questa pagina non ha ancora commenti