Creare dei threads.


Java Sun

Earthweb
(ex Gamelan)

Jars

Java Boutique

JavaWorld

PIP






  JSem: 5.2

   Un thread è un singolo flusso sequenziale di istruzioni che si esegue in un programma; un thread non è un programma, si esegue all'interno di un programma. Un programma può contenere più threads (programma multithread). Chiaramente se c'è un'unica CPU (Central Processing Unity) sul computer, un solo thread può essere eseguito ad un dato momento, ma la CPU passerà da un thread a l'altro per dare l'impressione della simultaneità. Ogni programma ha almeno un thread ("main thread").

   Per creare e manipolare dei threads in Java abbiamo a disposizione la classe java.lang.Thread e l'interfaccia java.lang.Runnable (e anche metodi della classe Object). In altri termini per creare un thread bisogna estendere la classe Thread o implementare l'interfaccia Runnable. In particolare se vogliamo creare un thread in un'applet, siccome l'applet deve estendere la classe Applet, bisognerà implementare l'interfaccia Runnable.

La classe Thread

La classe Thread definisce i metodi start() e run(). Per creare un thread estendendo la classe Thread bisogna chiamare start(). Più precisamente con l'operatore new si istanzia un oggetto, questo oggetto è vuoto e può solo chiamare start(). Il metodo start() crea le risorse del sistema per eseguire il thread e chiama run(). A questo punto il thread è nello stato Runnable. Il metodo run() deve essere sovrascritto; è questo metodo che definisce cosa il thread deve fare durante la sua esecuzione. Facciamo un esempio:

  
class ThreadEs1 extends Thread{

static String[] msg = {"Java", "e'", "un", "linguaggio", 
"veramente", "fantastico!"};

public static void main(String[] arg){

ThreadEs1 thread1 = new ThreadEs1("thread1: ");
ThreadEs1 thread2 = new ThreadEs1("thread2: ");
thread1.start();
thread2.start();
boolean th1vivo = true;
boolean th2vivo = true;

do{
	if(th1vivo && !thread1.isAlive()){
		th1vivo = false;
		System.out.println("Thread 1 e' morto");
	}
	if(th2vivo && !thread2.isAlive()){
		th2vivo = false;
		System.out.println("Thread 2 e' morto");
	}
}//fine do
while(th1vivo || th2vivo);
}//fine main

//costruttore
public ThreadEs1(String nome){
	super(nome);
}

//metodo run
public void run(){
	String nome = getName();
	for(int i=0; i < msg.length; i++){
		randomWait();
		System.out.println(nome + msg[i]);
	}
}

//metodo randomWait()
void randomWait(){
	try{
	sleep((int)(3000*Math.random()));
}catch(InterruptedException e){};
}
}//fine classe

Eseguendo più volte questo programma, potrete osservare che difficilmente avrete due volte di seguito lo stesso outpout (almeno sotto Windows).
Guardiamo un pò il codice.
La nostra classe estende Thread e presenta il costruttore:

public ThreadEs1(String nome){
	super(nome);
}

dove super si rifersice alla super classe Thread, infatti il costruttore
Thread(String nome) è definito in Thread (vedere la doc).
Nel metodo run() si usa il metodo getName() della classe Thread che ritorna, appunto, la stringa nome di cui sopra. Dopo c'è un ciclo for durante il quale il sistema stampa sul video le varie stringhe dell'array di stringhe msg; ma tra due valori successivi di i c'è una pausa, di durata aleatoria, data dal metodo randomWait() definito più avanti.
Nel metodo randomWait() si usa il metodo sleep() della classe Thread la cui definizione precisa è:
static void sleep(long millis) throws InterruptedException
questp metodo sospende, per il numero specificato di millisecondi, l'esecuzione del thread corrente. Il metodo lancia un'eccezione di tipo InterruptedException (che potrebbe capitare, per esempio, se un altro thread ha interotto il thread corrente), che bisogna catturare.
Passiamo adesso al blocco main.
Si inizia col istanziare (con l'operatore new) due oggetti della classe che poi chiamano il metodo start(); si definiscono anche due booleani che serviranno a testare lo stato dei nostri threads. Dopodichè compare un blocco do ... while.
Cogliamo l'occasione per fare una parentesi sull'istruzione do ... while.

L'istruzione do ... while
L'istruzione si presenta nella forma seguente:

	do{
	istr
	}
	while(cdz)

  • Il programma esegue l'istruzione (o le istruzioni) istr
  • Dopo avere eseguito istr, il programma testa la condizione cdz; se è verificata si torna al passo precedente, altrimenti si esce dal blocco do ... while e si passa all'istruzione successiva.
    Quindi do ... while assomiglia a while con la differenza che l'istruzione istr viene eseguita almeno una volta, anche se la condizione cdz non è verificata.


    Tornando al nostro esempio, il blocco do ... while usa il metodo isAlive(); questo metodo, di cui riparleremo più avanti, ritorna false se il thread è morto (o se è solo un new Thread che non ha ancora chiamato start()).
    A questo punto il codice di ThreadEs1 dovrebbe essere chiaro.

    L'interfaccia Runnable
    Il programma ThreadEs1 presenta l'inconveniente di estendere la classe Thread ed è, per esempio, inutilizzabile in un'applet. Si può rimediare a questo inconveniente implementando l'interfaccia Runnable; questa interfaccia ha un unico metodo: run().

    class ThreadEs2 {
    
    public static void main(String[] arg){
    
    ThreadEs1 thread1 = new Thread(new MyThR("thread1: "));
    ThreadEs1 thread2 = new Thread(new MyThR("thread2: "));
    thread1.start();
    thread2.start();
    boolean th1vivo = true;
    boolean th2vivo = true;
    
    do{
    	if(th1vivo && !thread1.isAlive()){
    		th1vivo = false;
    		System.out.println("Thread 1 e' morto");
    	}
    	if(th2vivo && !thread2.isAlive()){
    		th2vivo = false;
    		System.out.println("Thread 2 e' morto");
    	}
    }//fine do
    while(th1vivo || th2vivo);
    	}
    }
    //la classe MyThR (MyThreadRunnable)
    class MyThR implements Runnable{
    static String[] msg = {"Java", "e'", "un", "linguaggio",
    "veramente", "fantastico!"};
    String nome;
    //costruttore
    public MyThR(String nome){
    	this.nome = nome;
    }
    //metodo run dell'interfaccia
    public void run(){
    	for(int i=0; i < msg.length; i++){
    		randomWait();
    		System.out.println(nome + msg[i]);
    	}
    }
    //metodo randomWait()
    void randomWait(){
    	try{
    	sleep((int)(3000*Math.random()));
    }catch(InterruptedException e){};
    	}
    }

    Il programma ThreadEs2 è praticamente identico a ThreadEs1 e fornisce lo stesso outpout, l'unica differenza sta nel fatto che ThreadEs2 non estende la classe Thread e questo, come già osservato, può tornare utile.




  •  next		content		previous