produttore.java

import java.awt.*;
import java.applet.Applet;

public class produttore extends Applet implements Runnable {

Button reset;         // Azzera i campi e riavvia i thread
Label corrente;       // Numero corrente (uno ogni 200)
Label sincronizzato;  // Testo 'sincronizzato' o 'non sincronizzato'
Checkbox sincro;      // Comando per sincronizzare
TextArea errori;      // Lista degli errori

/* I due thread... */
Thread produttore = null;
Thread consumatore = null;

int base [];                          // I due numeri della serie (produttore)
int last = 0;                         // L'ultimo numero ricevuto (consumatore)
int ciclo = 0;                        // Contatore display (consumatore)
volatile boolean usaSincro = false;   // Flag di sincronizzazione
volatile StringBuffer buffer = null;  // Buffer di comunicazione

  /* Prepara l'interfaccia */
  public void init () {
    base = new int [2];               // Inizializza l'array dei due numeri
    base [0] = 1;                     // Primi valori della serie
    base [1] = 2;
    last = 0;                         // Inizializza consumatore

    setBackground (Color.white);      // Sfondo applet
    setLayout (new BorderLayout ());  // Layout con le cinque posizioni

    Panel np = new Panel ();          // Pannello superiore (corrente e stato)
    np.setLayout  (new FlowLayout ());// Che mette i compoinenti uno in fianco all'altro

    corrente = new Label ("0             "); // Lunga quanto il massimo numero, per dimensione corretta
    np.add (corrente);

    sincronizzato = new Label ("Non Sincronizzato");
    np.add (sincronizzato);
        
    add ("North",np);                 // Metto il pannello con i due testi a nord dell'applet

    errori = new TextArea(4, 50);
    errori.setEditable(false);
    add ("Center", errori);           // Aggiungo la lista con gli errori al centro nell'applet

    Panel sp = new Panel ();          // Un ultimo pannello
    sp.setLayout  (new FlowLayout ());// Che mette i compoinenti uno in fianco all'altro

    reset = new Button ("Riavvia");
    sp.add (reset);

    sincro = new Checkbox ("Sincronizzazione");
    sincro.setBackground (Color.white);
    sp.add (sincro);
        
    add ("South",sp);                         // Metto il pannello con il bottone ed il check a sud dell'applet
  }
	
  /* Deve far partire il calcolo */	
  public void start() {
    /* Thread del consumatore */
    if (consumatore == null) {                       // Se il thread non esiste ancora
      consumatore = new Thread(this, "consumatore"); // Lo crea 
      consumatore.start();                           // E lo fa partire
    }
    /* Thread del produttore */
    if (produttore == null) {                       // Se il thread non esiste ancora
      produttore = new Thread(this, "produttore");  // Lo crea 
      produttore.start();                           // E lo fa partire
    }
  }

  /* Se usciamo dalla pagina, elimina i thread */
  public void stop() {
    produttore.stop ();   // Ferma il produttore
    produttore = null;    // Ed azzera il puntatore, per la 'start'
    consumatore.stop ();  // Ferma il consumatore
    consumatore = null;   // Ed azzera il puntatore, per la 'start'
  }

  /* Metodo per sincronizzare il produttore.
   * Non lo faccio direttamente nel produttore perche' altrimenti
   * il produttore, sincronizzato, non viene interrotto */
  synchronized private void doProdSync () {
    notifyAll ();  // Notifica sull'applet stesso
  }

  /* Metodo produttore */
  private void doProduttore () {
  int i;
    if (buffer != null)                     // Se il consumatore non ha nacora 'consumato'
      return;                               // Ritorna in loop
    int newNum = base [0] + base [1];       // Calcola il nuovo n umero
    base [0] = base [1];                    // Aggiorna l'array degli ultimi due valori
    base [1] = newNum;
    if (newNum < 0) {                       // Supera la frontiera del segno... 
      base [0] = 1;                         // Reinizializza la macchina
      base [1] = 2;
      newNum = 0;
    }
    String temp = String.valueOf (newNum);  // Converte in stringa il risultato
    buffer = new StringBuffer (40);         // Crea un nuovo buffer vuoto
    for (i = 0; i < temp.length (); i++) {
      if (buffer != null) {                 // Se il buffer non e' stato (per disgrazia) eliminato
        buffer.append (temp.charAt (i));    // Aggiunge il prossimo carattere al buffer
      }
      Thread.yield ();                      // E cede il controllo
    }
    if (usaSincro) {                        // Se e' attivo il sincronismo
      doProdSync ();                        // Chiama ilo metodo per riavviare il consumatore
    }
  }

  /* Metodo del consumatore */
  synchronized private void doConsumatore () {
    if (usaSincro) {                               // Se e' attivo il sincronismo
      try {
        wait ();                                   // Attende il segnale dal produttore
      } catch (InterruptedException e) {
      }
    } else {
      if (buffer == null || buffer.length () == 0) // Altrimenti se non ha il buffer o il buffer e' vuoto
        return;                                    // Ritorna
    }
    int nuovo = java.lang.Integer.parseInt (buffer.toString ()); // Converte il buffer in numero
    buffer = null;                                 // E lo libera
    if ((ciclo % 200) == 0)                        // Se e' il momento
      corrente.setText (String.valueOf (nuovo));   // Stampa il valore corrente
    if (nuovo < last && nuovo != 0) {              // Se il valore non e' in sequenza (e non e' inizializzazione)
      errori.appendText (String.valueOf (nuovo) + " quando l'ultimo era " + String.valueOf (last) + "\n");
                       // Scrivo nel testo l'errore
    } else {                                       // Se invece e' in sequenza (o e' 0, inizializzazione)
      last = nuovo;                                // Aggiorna l' "ultimo valore"
    }
    
  }

  /* Metodo che esegue il 'lavoro duro' - azione */
  public void run() {
    // Questo metodo viene invocato per ogni thread dell'Applet, quindi deve
    // eseguire il lavoro solo nel caso il thread sia quello dell'animazione,
    // uno o l'altro
    if (Thread.currentThread() == produttore) {
      while (true) {                          // Loop infinito
        doProduttore ();
        try {
          Thread.sleep(100);                  // Attende 100 mS (per cosmesi...)
        } catch (InterruptedException e){     // Nessuna azione
        }
      }
    } else if (Thread.currentThread() == consumatore) {
      while (true) {                          // Loop infinito
        doConsumatore ();
        Thread.yield ();                      // passa il controllo
      }
    }
  }

  // Gestione di tutti i bottoni (normali, check e radio)
  public boolean action(Event event, Object arg) {
    if (event.target == reset) {
      stop();                           // Ferma i due thread
      errori.setText ("");              // Vuota il campo degli errori
      corrente.setText ("0");           // Azzera il 'valore corrente'
      base [0] = 1;                     // Inizializza l'array degli ultimi valori
      base [1] = 2;
      last = 0;                         // Inizializza le variabili del 'consumatore'
      ciclo = 0;
      buffer = null;                    // Elimina il buffer di comunicazione
      usaSincro = sincro.getState();    // Legge il valore del flag di sincronizzazione
      // Aggiorna la label del modo di funzionamento
      sincronizzato.setText ((usaSincro) ? "Sincronizzato" : "Non Sincronizzato");
      start();                          // Finalmente riavvia i due thread
    }
    return true;
  }
}