CodeGym /Java Course /Modulo 3 /Sincronizzatori: sincronizzazione dell'accesso alle risor...

Sincronizzatori: sincronizzazione dell'accesso alle risorse in Java

Modulo 3
Livello 19 , Lezione 4
Disponibile

Semaforo

I semafori vengono solitamente utilizzati quando è necessario limitare il numero di thread quando si lavora con il file system. L'accesso a un file o altra risorsa condivisa è controllato tramite un contatore. Se il suo valore è maggiore di zero, l'accesso è consentito, ma allo stesso tempo il contatore diminuirà.

Nel momento in cui il contatore restituisce zero, il thread corrente verrà bloccato fino a quando la risorsa non verrà rilasciata da un altro thread. Il parametro numero di autorizzazioni deve essere impostato tramite il costruttore.

Devi selezionare questo parametro individualmente, a seconda della potenza del tuo computer o laptop.

public class Main {

   public static void main(String[] args) {
       Semaphore sem = new Semaphore(1);
       CommonResource res = new CommonResource();
       new Thread(new MyThread(res, sem, "MyThread_1")).start();
       new Thread(new MyThread(res, sem, "MyThread_2")).start();
       new Thread(new MyThread(res, sem, "MyThread_3")).start();
   }
}

class CommonResource {
   int value = 0;
}

class MyThread implements Runnable {
   CommonResource commonResource;
   Semaphore semaphore;
   String name;
   MyThread(CommonResource commonResource, Semaphore sem, String name) {
       this.commonResource = commonResource;
       this.semaphore = sem;
       this.name = name;
   }

   public void run() {

       try {
           System.out.println(name + "waiting permission");
           semaphore.acquire();
           commonResource.value = 1;
           for (int i = 1; i < 7; i++) {
               System.out.println(this.name + ": " + commonResource.value);
               commonResource.value++;
               Thread.sleep(150);
           }
       } catch (InterruptedException e) {
           System.out.println(e.getMessage() + " " + name);
           Thread.currentThread().interrupt();
       }
       System.out.println(name + "releases permission");
       semaphore.release();
   }
}

CountDownLatch e altri

CountDownLatch : consente a più thread di attendere fino al completamento di un determinato numero di operazioni eseguite su altri thread. Un esempio è l'installazione di un'applicazione: essa non si avvierà finché non si accettano le condizioni d'uso, finché non si seleziona una cartella dove installare un nuovo programma e così via. Esiste uno speciale metodo countDown() per questo : questo metodo decrementa il contatore del conto alla rovescia di uno.

Non appena il conteggio va a zero, tutti i thread in attesa in await continueranno il loro lavoro e tutte le successive chiamate di await passeranno senza attendere. Il contatore del conto alla rovescia è un contatore una tantum e non può essere azzerato.

CyclicBarrier : utilizzato per sincronizzare un determinato numero di thread in un punto. La barriera viene raggiunta quando N thread chiamano il metodo await(...) e bloccano. Successivamente, il contatore viene ripristinato al suo valore originale e i thread in attesa verranno rilasciati. Inoltre, se necessario, è possibile eseguire codice personalizzato prima di sbloccare i thread e reimpostare il contatore. Per fare ciò, un oggetto con un'implementazione dell'interfaccia Runnable viene passato attraverso il costruttore .

Exchanger<V> : la classe Exchanger è destinata allo scambio di dati tra thread. Viene digitato e digita il tipo di dati che i thread devono scambiare.

I dati vengono scambiati utilizzando l'unico metodo exchange() di questa classe :

V exchange(V x) throws InterruptedException
V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException

Il parametro x rappresenta il buffer di dati da scambiare. La seconda forma del metodo definisce anche il parametro timeout , il timeout e unit , il tipo di unità di tempo da utilizzare per il parametro timeout .

La classe Phaser consente di sincronizzare i thread che rappresentano una singola fase o fase nell'esecuzione di un'azione complessiva. Phaser definisce un oggetto di sincronizzazione che attende il completamento di una determinata fase. Il Phaser passa quindi alla fase o fase successiva e attende che venga completata di nuovo.

Quando si lavora con la classe Phaser , è comune creare prima il suo oggetto. Successivamente, dobbiamo registrare tutti i partecipanti. Per registrarsi per ogni partecipante, viene chiamato il metodo register() , oppure è possibile fare a meno di questo metodo passando il numero richiesto di partecipanti al costruttore Phaser .

Quindi ogni partecipante esegue un certo insieme di azioni che compongono la fase. E il sincronizzatore Phaser attende che tutti i partecipanti abbiano completato l'esecuzione della fase. Per informare il sincronizzatore che la fase è terminata, il partecipante deve chiamare il metodo arrive() o arriveAndAwaitAdvance() . Il sincronizzatore passa quindi alla fase successiva.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION