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; } }