Home
Home
Tutorials
   PHP
   Java
   Tutti...
Manuali
SmartImage
Marketing
Downloads
Contatti
Affiliati

  Da vedere
Hosting
Statistiche per siti
Corsi per webmaster
Hardware
Processori


  OnFocus
Sostituire parole o testi in una variabile

PHP 5 ad oggetti: overriding e keyword final

Installare Java

  Siti Amici
Miki News
Giochi gratis
Areagratis
Baratto Online
AI Machines
Guide e Manuali Gratis
FreeOnLine
SpazioLink.com
Ricerca Internet
Sms Game
Boutique online
Appunti universitari
Add to Technorati Favorites

Tutti i siti amici
Diventa Affiliato

 


Autore: Claudio Venturini
Categoria: java
Livello: normale Livello normale

Cenni di programmazione multi-threading - parte 4

Coordinare i thread

In questa quarta e ultima parte del tutorial approfondiamo il modello produttore - consumatore già visto nella parte terza. Come ho già mostrato, il monitor agisce come un direttore d'orchestra, in cui l'orchestra è composta dai thread. Il monitor in particolare gestisce un buffer, o una qualsiasi altra struttura dati, a cui i thread devono accedere in lettura o scrittura. Nell'esempio presentato il buffer non aveva dimensione definita, quindi i thread potevano sempre inserirvi nuovi elementi. Estendiamo l'esempio imponendo che il buffer abbia una dimensione massima. In questo caso è necessario coordinare i produttori in modo che "smettano" di produrre elementi, quando il buffer è pieno.

La soluzione finale

Per evitare l'overflow del buffer sfruttiamo ancora una volta il meccanismo di wait() e notify() per addormentare i produttori quando il buffer è pieno, e svegliarli appena si libera almeno un posto. L'unico metodo da modificare è il metodo accodaRichiesta() del monitor. Esso dovrà controllare la dimensione del buffer. Se questa è uguale alla massima dimensione possibile allora deve addormentare il produttore che ha chiamato il metodo per accodare la richiesta. Ecco il codice:

import java.util.Vector;

public class 
Monitor {
  // Coda delle richieste private
  Vector<StringcodaRichieste = new Vector<String>();
  // Dimensione max della coda
  private int max 0;

  /*
   * Crea il monitor impostando la
   * dimensione massima del bufffer
   * (coda) gestito.
   */
  public Monitor(int max){
    this.max max;
  }

  // Preleva la prima richiesta in coda
  public synchronized String prelevaRichiesta(){
    while (codaRichieste.size() == 0){
      try {
        wait();
      }
      catch (InterruptedException e){
        e.printStackTrace();
      }
    }

    String element codaRichieste.remove(0);
    notifyAll();
    return element;
  }

  // Accoda una nuova richiesta
  public synchronized void accodaRichiesta(String richiesta){
    System.out.println("Elementi buffer: " codaRichieste.size());
    while (codaRichieste.size() == max){
      try {
        wait();
      }
      catch (InterruptedException e){
        e.printStackTrace();
      }
    }

    codaRichieste.addElement(richiesta);
    notifyAll();
  }

Alcuni commenti. Si nota subito come il comportamento del metodo accodaRichiesta() sia ora quasi identico al metodo prelevaRichiesta(), a differenza che al posto di controllare se il buffer è vuoto, controlla se è pieno. Se è pieno addormenta il produttore che ha chiamato il metodo. Se invece non è pieno inserisce la richiesta e utilizza notifyAll() per svegliare gli eventuali thread consumatori in attesa di un elemento da prelevare.
Anche prelevaRichiesta() è stato modificato inserendo un notifyAll(), necessario per svegliare eventuali produttori in attesa che si liberi un posto nel buffer. Infine è stato aggiunto un attributo max, inizializzato dal costruttore, che rappresenta la dimensione massima del buffer.
Tutte le altre classi rimangono invariate. Bisogna solo ricordarsi, nel main(), di passare al costruttore del monitor la dimensione del buffer.

Provate ad avviare l'esempio: noterete che la dimensione del buffer pian piano cresce fino ad arrivare al valore impostato in max. Dopodichè i thread continuano ad addormentarsi e svegliarsi in base ai posti disponibili nel buffer. Se l'effetto non è immediatamente evidente cambiate i tempi di attesa impostati con sleep(): in particolare allungate i tempi del consumatore. In questo modo il buffer ha tempo di riempirsi prima che intervenga un consumatore a svuotarlo.

Un'applicazione reale

Ovviamente questo modello è diffusissimo. Nel caso del webserver, ovviamente esiste un limite massimo di richieste contemporanee gestibili. Ciò è necessario per non saturare il server. i può quindi pensare che le richieste vengano inserite in un buffer e gestite secondo questo modello. Il webserver molto probabilmente avrà un solo thread produttore, in quanto la porta di ascolto (80) è unica. Questo thread andrà a inserire le richieste nel buffer, e se questo è pieno verrà addormentato. Se il buffer si satura e rimane saturo per un certo periodo di tempo, verrà ritornato all'utente un messaggio di timeout, che indica la saturazione del webserver. E' il classico messaggio "Spiacenti, troppe connessioni simultanee, riprova più tardi".

Cenni di programmazione multi-threading - parte 3 Precedente Indice Successivo Iniziare con la tecnologia Java Servlet
Cenni di programmazione multi-threading - parte 3 Iniziare con la tecnologia Java Servlet