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