Interfața Runnable

Interfața java.lang.Runnable trebuie implementată de orice clasă care nu este descendentă a clasei java.lang.Thread, dar ale cărei instanțe trebuie tratate ca niște fire de execuție. Singura metodă a acestei interfețe este
    public void run()
care are același rol cu cea din clasa Thread.
 
Necesitatea implementării interfeței Runnable apare atunci când dorim să creem o clasa de fire de execuție care nu extinde clasa Thread. Motivul ar putea fi, de exemplu, cel că clasa nou creată, B, trebuie sa extindă o alta clasă, A, care nu este descendentă a clasei Thread  Se știe că  în Java nu există moștenire multiplă, deci clasa B nu poate avea ca superclase atât clasa A, cât și clasa Thread. În acest caz, vom crea o clasă B care extinde clasa A și implementeaza interfața Runnable, care conține metoda run().

Utilizarea instanțelor claselor cu interfața Runnable se face, punându-le ca argumente ale următorilor constructori ai clasei Thread:
    public Thread(Runnable target)
    public Thread(Runnable target, String name)
O instanță a clasei Thread creată cu un astfel de constructor, se comportă ca și cum ar fi instanța unei extensii a clasei Thread care ar conține metoda run() a obiectului target cu interfața Runnable.
 
Exemplul 1
În fișierul DouaFireAR.java se dă un exemplu de aplicație similară cu cea din fișierul DouaFireA1.java, cu deosebirea că clasa Fir nu extinde clasa Thread, ci implementează interfața Runnable. Fragmentele de program modificate sunt puse în evidența în textul sursă de mai jos prin caractere aldine (ingroșate).
 
/* Crearea si utilizarea unei clase cu interfata Runnable.
   Se foloseste metoda yield() pentru a ceda controlul altui fir de
   aceeasi prioritate.
   Se creeaza doua fire de aceeasi prioritate (Thread.NORM_PRIORITY),
   utilizand ca argument al constructorului instante ale clasei
   Fir cu interfata Runnable.
*/

class DouaFireAR {

  /* Clasa cu interfata Runnable */
  static class Fir implements Runnable {

    /* Definirea metodei run() din interfata Runnable */
    public void run() {
     System.out.println("Incepe executarea firului "+
       Thread.currentThread().getName());
     for(int i=0; i<6; i++) {
      System.out.println("Firul "+
        Thread.currentThread().getName()+" ciclul i="+i);
      Thread.yield(); // cedarea controlului procesorului
     }
    }
  } /* incheierea clasei Fir */

  public static void main(String args[]) throws Exception {
    Thread fir1, fir2;
    System.out.println("Se creeaza firul Alpha");
    fir1=new Thread(new Fir(), "Alpha");
    System.out.println("Se creeaza firul Beta");
    fir2=new Thread(new Fir(), "Beta");
    System.out.println("Se pune in executie firul Alpha");
    fir1.start();
    System.out.println("Se pune in executie firul Beta");
    fir2.start();
    System.out.println("Sfarsitul metodei main()");
  } /* Sfarsitul metodei main() */
}

Comparând cu Exemplul 2 din sectiunea Clasa Thread, constatăm cele ce urmează.

 - Clasa Fir nu mai extinde clasa Thread, ci implementeaza interfața Runnable.
 - În metoda run() a clasei Fir s-a avut în vedere că aceasta nu extinde clasa Thread și deci nu moștenește metodele ecesteia. În consecință:
    . metoda statică yield() a clasei Thread a fost invocată sub forma Thread.yield();
    . pentru a obține o referință la instanța curentă a clasei Thread, necesară invocării metodei getName(), s-a folosit metoda statică Thread.getCurrentThread().
  - Crearea celor două fire de execuție în metoda main() s-a făcut folosind un constructor al clasei Thread, căruia i s-au dat ca parametri o instanță a clasei Fir și numele firului respectiv, de exemplu:
    fir1=new Thread(new Fir(), "Alpha");

Dacă se compilează și se execută această aplicație, se obțin exact aceleați rezultate ca în cazul când s-a recurs la extinderea clasei Thread.


 
Exemplul 2
În fișierul Bondari.java este dat un exemplu de aplicație, în care se pot crea mai multe fire de execuție, fiecare având propria sa interfață grafică. Fiecare fir de execuție este o instanța a clasei Bondar, care extinde clasa JFrame și  implementează interfața Runnable. Aplicația propriu-zisă (care conține metoda main()) este clasa Bondari, care extinde și ea clasa JFrame.

Fereastra principală a aplicației (interfața clasei Bondari) conține numai un buton cu inscripția "Creare nou bondar". De câte ori se apasă acest buton, se creeaza o noua instanță a clasei Bondar. 

Clasa Bondar are propria ei interfață grafică, în care există două rigle pentru ajustarea perioadei și amplitudinii și o fereastră în care evoluează "bondarul". Acesta este un mic dreptunghi roșu, a cărui mișcare o simuleaza pe cea a unei insecte în zbor. Amplitudinea, cât și perioada deplasărilor "bondaruliui" sunt ajustate cu cele două rigle. Dacă se acționeaza butonul de închidere a ferestrei "bondarului" (cel marcat cu X din colțul dreapta-sus), se încheie ciclul de viață al firului de execuție respectiv. Aceasta are loc, întrucat ciclul din metoda run() a firului continuă cât timp variabila booleana esteViu are valoarea true. Când se acționeaza butonul de închidere a ferestrei "bondarului", evenimentul este captat de metoda windowClosing() a clasei SfarsitBondar, care pune variabila esteViu a "bondarului" respectiv la valoarea false.

Dacă se acționează butonul de închidere a ferestrei principale (cea care conține butonul "Creare nou bondar"), evenimentul este captat de metoda windowClosing() a clasei Iesire, astfel că se execută metoda exit(0). Efectul este încheierea execuției tuturor firelor și oprirea mașinii virtuale Java.



© Copyright 2000 - Severin BUMBARU, Universitatea "Dunărea de Jos" din Galați