Fire de Executie Java

INTRODUCERE

Java este un limbaj de programare orientat-obiect, puternic tipizat, conceput de către James Gosling la Sun Microsystems (acum filială Oracle) la începutul anilor ʼ90, fiind lansat în 1995. Cele mai multe aplicații distribuite sunt scrise în Java, iar noile evoluții tehnologice permit utilizarea sa și pe dispozitive mobile gen telefon, agendă electronică, palmtop etc. În felul acesta se creează o platformă unică, la nivelul programatorului, deasupra unui mediu eterogen extrem de diversificat. Acesta este utilizat în prezent cu succes și pentru programarea aplicațiilor destinate intranet-urilor.

Limbajul împrumută o mare parte din sintaxă de la C și C++, dar are un model al obiectelor mai simplu și prezintă mai puține facilități de nivel jos. Un program Java compilat, corect scris, poate fi rulat fără modificări pe orice platformă care este instalată o mașină virtuală Java (engleză Java Virtual Machine, prescurtat JVM). Acest nivel de portabilitate (inexistent pentru limbaje mai vechi cum ar fi C) este posibil deoarece sursele Java sunt compilate într-un format standard numit cod de octeți (engleză byte-code) care este intermediar între codul mașină (dependent de tipul calculatorului) și codul sursă.

Mașina virtuală Java este mediul în care se execută programele Java. În prezent, există mai mulți furnizori de JVM, printre care Sun, IBM, Bea, Oracle, FSF. În 2006, Sun a anunțat că face disponibilă varianta sa de JVM ca open-source.

Există 3 platforme Java furnizate de Sun Microsystems:

Java Platform, Micro Edition (Java ME) — pentru hardware cu resurse limitate, gen PDA sau telefoane mobile,

Java Platform, Standard Edition (Java SE) — pentru sisteme gen workstation, este ceea ce se găseste pe PC-uri,

Java Platform, Enterprise Edition (Java EE) — pentru sisteme de calcul mari, eventual distribuite.

CAPITOLUL I: LIMBAJUL JAVA

Ce este JAVA ?

Java este un limbaj de programare dezvoltat de JavaSoft, companie în cadrul firmei Sun Microsystems.

este complet orientat pe obiecte și oferă posibilitatea real\de refolosire a codului (care este de fapt promisiunea făcută la apariția programării orientate pe obiecte).

este neutru din punct de vedere arhitectural, cu alte cuvinte Java este un limbaj independent de platforma de lucru, aceeași aplicație rulând, fără nici o modificare, pe sisteme diferite cum ar fi Windows, UNIX sau Macintosh, lucru care aduce economii substanțiale firmelor care dezvoltă aplicații pentru Internet.

limbajul Java este modelat după C și C++, trecerea de la C, C++ la Java făcându-se foarte ușor.

elimină sursele frecvente de erori ce apar în programare prin eliminarea pointerilor, administrarea automată a memoriei și eliminarea fisurilor de memorie printr-o procedură de colectare a “gunoiului” care rulează în fundal;

este cel mai sigur limbaj de programare disponibil în acest moment, asigurând mecanisme stricte de securitate a programelor concretizate prin: verificarea dinamică a codului pentru detectarea secvențelor periculoase, impunerea unor reguli stricte pentru rularea programelor lansate pe calculatoare aflate la distanță (acestea nu au acces la rețeaua locală, la fișierele stocate în sistemul local și nu pot lansa în execuție programe locale), etc.

permite creearea unor documente Web imbunătățite cu animație și multimedia.

a fost proiectat pentru a fi folosit în medii distribuite și sisteme deschise.

Evoluția limbajului JAVA

În 1991, firma SUN, mergând pe direcția dezvoltării sistemelor deschise de lucru în rețea, a creat un proiect de lucru numit Green, care avea drept scop punerea la punct a unor procesoare care să poată rula pe diferite tipuri de aparate și punerea la punc a unui sistem care să poată rula pe platforme diferite. Planul inițial prevedea dezvoltarea proiectului în C++, dar au apărut foarte multe probleme în încercarea de dezvoltare a compilatorului de C++. Ca urmare, James Gosling, membru al grupului Green, a început să lucreze la dezvoltarea unui nou limbaj, numit Oak, care, mai tarziu, avea să se numească Java. De asemenea grupul Green avea să-și schimbe numele întâi în FirstPerson, apoi în JavaSoft.

Abia după ce a fost înființată compania Netscape Communications Corporation, cei de la JavaSoft s-au orientat către Internet și Web, mediul multiplatformă distribuit al rețelei Internet fiind perfect pentru testarea proiectului.

În present, licența pentru tehnologia Java a fost acordată unor firme precum IBM, Microsoft, Sillicon Graphics, Adobe și Netscape.

Limbajul Java

Java este un limbaj de programare conceput de Sun Microsystems la începutul anilor 90.

A fost conceput ca un limbaj de programare orientat-obiect foarte puternic,  "cross-platform" și "device-independent", ceea ce înseamnă că programul compilat trebuie să ruleze atât pe PC-uri, MAC-uri sau calculatoare cu platforma UNIX.

Browser-ele creează un mediu pentru rularea applet-urilor Java, numit Java Virtual Machine. Acesta oferă independenta platformei pentru applet-urile Java.

Denumirea de applet se referă la orice mini-aplicatie creată cu ajutorul limbajului Java. Creare unui applet nu face obiectul acestui ghid. Applet-urile sunt programe compilate separate ce au extensia ".class". Acestea sunt descărcate împreună cu pagină web prin folosirea tag-ului <APPLET>.

Sintaxa HTML pentru folosirea tag-ului <APPLET> și a tag-ului său asociat <PARAM>, este următoarea:

< APPLET

          [CODEBASE = directorApplet]

          [CODE = clasaApplet]

          [ALT = textAlternativ]

          [NAME = numeInstantaApplet]

          WIDTH = latimeInPixeli

          HEIGHT = inaltimeInPixeli

          [ALIGN = aliniere]

          [VSPACE = spatiuVertical]

          [HSPACE = spatiuOrizontal] >

[< PARAM NAME = numeParametru_1 VALUE = valoare_1 >]

          . . .

[< PARAM NAME = numeParametru_n VALUE = valoare_n >]

 [text HTML alternativ]

</APPLET>

Atributele puse între paranteze pătrate sunt opționale. Semnificația atributelor este următoarea:

< PARAM NAME = numeParametru1 VALUE = valoare1 >

Tag-urile <PARAM> sunt folosite pentru specificarea parametrilor unui applet. Acești parametri permit utilizatorului să personalizeze aspectul său comportarea unui applet fără a-i schimba codul și recompila clasele.

text HTML alternativ

Este textul ce va fi afișat în cazul în care browser-ul nu înțelege tag-ul <APPLET>. Browser-ele care înțeleg Java vor ignora acest text.

Cum este rulat un program Java ?

Interpretorul Java transformă codul de octeți într-un set de instrucțiuni mașină, întârzierea interpretării fiind însă foarte mică datorită asemănării dintre codul de octeți și limbajul de asamblare și din acest motiv execuția se face aproape la fel de repede ca în cazul programelor compilate.

Cum este obținută neutralitatea arhitecturală a limbajului Java? Cu alte cuvinte, cum este posibilă portarea codului de octeți pe calculatoare diferite?

Truc: codul sursă este compilat nu pentru calculatorul pe care se lucrează ci pentru un calculator inexistent, acest calculator imaginar fiind numit Mașina virtuală Java (Java Virtual Machine). Interpretorul acționează apoi ca un intermediar între Mașina virtuală Java și mașina reală pe care este rulat programul.

Java și conceptele programării orientate pe obiecte

Limbajul Java este următorul pas logic în domeniul limbajelor de programare, și se bazează pe cel mai popular limbaj de programare al momentului C++. În Java se pot obține programe cu aspectul și comportarea programelor C++, dar beneficiind de avantajele oferite de un limbaj proiectat special pentru POO. Java renunță complet la programarea procedurală specifică C-ului și vă obligă să folosiți conceptele solide ale POO. Conceptele programării orientate pe obiecte cuprind:

Obiectele

Incapsularea și transmiterea de mesaje

Clasele

Bibliotecile (numite pachete, în Java)

Moștenirea

Modificatorii de acces

Caracteristicile Obiectelor:

unitatea elementară a POO;

starea obiectului este dată de variabile de instanță;

comportamentul obiectului este dat metode ușor de refolosit, actualizat, întreținut

Incapsularea și transmiterea de mesaje :

Clasele – caracteristici:

incapsulează obiecte;

o singură clasă poate fi folosită pentru instanțierea mai multor obiecte;

Pachetele: colecție de clase înrudite

Moștenirea permite:

extinderea funcționalității unor clase existente;

refolosirea codului

Modificatorii de acces: controlează accesul la metodele și variabilele obiectelor. Acestea pot fi:

Private – accesibile doar obiectelor din aceeași clasă;

Protejate – accesibile obiectelor din aceeași clasă și din subclasele clasei respective.

Prietenosase – (nivelul de accesibilitate prestabilit) accesibile tuturor claselor din pachetul current;

Publice – accesibile tuturor claselor din orice pachet.

Programarea în limbajul Java. Caracteristicile de bază al limbajului Java

Folosirea în medii de rețea distribuite

Java a fost proiectat pentru un mediu complex cum este Internetul și de aceea trebuie să poată rula pe platforme eterogene distribuite. Acest lucru este posibil deoarece:

este neutru din punct de vedere arhiectural = programele pot fi rulate pe orice platformă care are instalat mediul Java;

are un grad ridicat de portabilitate = conține obictecte care pot fi folosite pe platforme eterogene și respectă standardele IEEE (Institue of Electrical and Electronics Engineers) pentru structurile de date (folosirea întregilor, a numerelor în virgulă mobilă, a șirurilor, etc);

este distribuit = poate folosi atât obiecte memorate local cât și obiecte stocate pe calculatoare aflate la distanță;

este compatibil cu mediile de lucru în rețea (poate fi utilizat în rețele complexe) și acceptă direct protocoalele de rețea obițnuite cum ar fi FTP și HTTP.

Asigurarea performanței ridicate:

Compilatorul și sistemul de execuție oferă o viteză ridicată rulării programelor;

Are incorporate posibilități de execuție multifilară (rularea simultană a mai multor procese) folosind un sistem de acordare de priorități proceselor ce trebuie executate. Printre procesele care rulează în fundal sunt cele de “colectare a gunoiului” și de gestionare a memoriei.

Refolosirea codului și fiabilitatea:

Java este un limbaj dinamic, lucru asigurat prin întârzierea legării obiectelor și legarea dinamică a claselor în timpul execuției, ceea ce împiedică apariția erorilor în cazul schimbării mediului de lucru după compilarea programului sursă.

Fiabilitatea este asigurată prin eliminarea pointerilor, prin folosirea verificării dinamice a limitelor și prin gestionarea automată a memoriei, înlăturându-se posibilitatea fisurilor și violărilor de memorie.

O altă cale de evitare a erorilor este verificarea structurilor de date atât la compilare cât și în timpul execuției.

Asigurarea securității:

Interzice accesul la stiva sistemului, la zona liberă de memorie și la secțiunile protejate de memorie;

Verifică validitatea codului semnalând următoarele:

Violările de acces

Conversiile ilegale de date

Valori și parametri incorecți

Modificarea claselor sau folosirea incorectă a acestora

Depășirea stivei în partea superioară sau inferioară

Activități suspecte sau neautorizate

Structura limbajului Java

Aplicații și miniaplicații:

Miniaplicație (applet), reprezintă un program Java creat pentru a fi folosit în sitemul WWW. Applet-urile necesită un program de vizualizare extern : browser Web sau un program specializat de vizualizare (applet viewer).

Aplicație (app), reprezintă un program Java care poate fi rulat independent.

Spații de nume:

Pentru evitarea conflictelor legate de spațiile de nume, fiecare componentă a unui nume este îmbrăcată în conformitate cu unul din următoarele niveluiri:

0 – spațiul de nume al pachetului

1 – spațiul de nume al unității de compilare

2 – spațiul de nume al tipului

3 – spațiul de nume al metodei

4 – spațiul de nume al blocului local

5 – spațiul de nume al blocului îmbrăcat

Interpretorul este responsabil pentru menținerea și trrea și translatarea spațiului de nume. Spațiile de nume sunt separate prin punct. Ex. java.lang.System.out.println() – calea completă.

Pachetele Java din biblioteca originală de pachete sunt referite prin java urmat de numele pachetului (java.lang).

În cazul în care nu există confuzii, poate fi folosită o variantă prescurtată a apelului (interpretorul folosește prima potrivire de nume descoperită); apelul la println() se putea face și prin System.out.println()

Structuri de denumire a programelor. Fișiere sursă java ®(compilare)® cod de octeți format din unități de compilare. Pentru fiecare clasă declarată în codul sursă este generată o unitate de compilare stocată într-un fișier separat cu extensia .class. Unitățile de compilare Java conțin:

Instrucțiuni de pachet

Instrucțiuni de import

Declarații ale claselor și interfațelor

(structura de bază a unui program Java)

  Instrucțiuni de pachet. Sunt folosite pentru a preciza poziția pachetelor folosite într-o aplicație. În mod implicit, Java folosește calea de acces curentă și presupune că fișierele cu cod compilat se află în directorul curent la rularea programului.

Pentru ca obiectele și clasele să respecte o structură ierarhică diferită de cea prestabilită trebuie inclusă în codul sursă o instrucțiune de pachet:

package NumePachet

În cazul când se folosesc mai multe niveluri, instrucțiunea va avea forma:

package MyPackages.NumeSubPachet

Numele de pachete de pe fiecare nivel al spațiului de nume trebuie să reflecte structura de directoare a sistemului de fișiere, deoarece Java transformă numele pachetelor în căi de acces pentru localizarea claselor și a metodelor asociate pachetelor. De exemplu într-un sistem Windows 95/NT numele de pachet MyPackages. Pachetel va fi transformat în directorul \MyPackages\Pachetel unde Java va căuta pachetul respectiv.

Instrucțiuni de import.

Java conține un set de funcții principale, accesibile global, și care sunt localizate în pachetul java .lang. Pentru a obține accesul la alte pachete, clase și obiecte care nu se află în această bibliotecă, se folosesc instrucțiuni de import, care ajută compilatorul Java să regăsească metodele corespunzătoare și să evite conflictele de nume.

De exemplu, pentru a apela metoda Button din pachetul java.awt (awt = Abstract Window Toolkit) se folosește instrucțiunea java.awt.Button. O metodă mai eficientă este de a importa metoda import java.awt.Button și de a apela metoda doar prin instrucțiunea Button.

Cea mai uzuală metodă de import este importul la cerere, care spune compilatorului să importe numai clasele de care este nevoie în program: import java.awt.* pentru a nu face disponibile toate clasele din java.awt.

Declarațiile de clasă.

În Java toate clasele sunt derivate dintr-o clasă sistem numită Object. Object este rădăcina ierarhiei de clase, toate metodele și variabilele clasei fiind disponibile celorlalte clase. În mod implicit, toate clasele sunt private. Declarațiile de clasă, fără modificatori de acces, au aceeași sintaxă ca în C++:

class nume_clasa

{

//metode si variabile asociate clasei

}

Java acceptă numai moștenirea simplă a claselor, fiecare clasă având așadar un singur părinte, numit superclasă. În scimb, Java permite moștenirea multiplă a metodelor claselor, prin intermediul interfe]elor claselor.

Declarațiile de interfață.

Interfațele sunt clase abstracte. Diferența majoră față de o clasă este aceea că interfațele nu pot stoca date. De asemenea, nu pot conține implementări ale metodelor ci doar declarații ale acestora.

O clasă poate să implementeze una sau mai multe interfațe și poate să partajeze aceaași interfață cu alte clase sau instanțe ale unei clase. Declarațiile de interfață fără modificatori au următorul format:

interface nume_interfata {

//metode si variabile statice asociate interfetei

}

Declarațiile de clase care folosesc interfațe au următorul format:

class nume_clasa implements nume_interfata {

//corpul clasei

}

Un alt format poate fi:

class nume_clasa implements nume_interfata1,…,nume_interfataN {

//corpul clasei

}

 Singura deficiență a folosirii interfațelor este aceea că necesită legare dinamică, ceea ce reduce performanțele execuției. Sunt însă mai eficiente decât moștenirea multiplă din C++, deoarece reduc suprasarcina de execuție.

CAPITOLUL II: FIRE DE EXECUȚIE

2.1. Ce sunt firele de execuție?

O aplicație Java rulează în interiorul unui proces al sistemului de operare. Procesul constă în segmente de cod și segmente de date mapate într-un spațiu virtual de adresare. Fiecare proces deține un număr de resurse alocate de către sistemul de operare, cum ar fi fișiere deschise, zone de memorie alocate dinamic sau fire de execuție. Resursele alocate procesului sunt eliberate la terminarea execuției procesului.

Un fir de execuție este unitatea de execuție a unui proces. Fiecărui fir de execuție i se asociază o secvență de instrucțiuni, un set de regiștri CPU și o stivă. Procesul nu execută instrucțiuni, este un spațiu de adresare comun pentru unul sau mai multe fire de execuție. Firele de execuție sunt cele care execută instrucțiunile.

Firele de execuție seamănă cu procesele, pot fi la fel planificate pentru execuție. Principala diferență este că firul se execută în spațiul de adresare al procesului căruia aparține și poate modifica valori care sunt văzute și de celelalte fire care aparțin aceluiași proces. Din această cauză apare necesitatea ca firele să comunice între ele, adică trebuie sincronizat accesul la datele utilizate în comun. Sincronizarea asigură siguranța datelor, adică prin sincronizare se previn situațiile ca un fir să modifice o variabilă care este tocmai utilazată de către un alt fir de execuție.

Fir de execuție = Secvența de instrucțiuni + un set de registi CPU + o stivă

Java fiind un limbaj interpretat, procesul deține codul interpretorului, iar codul binar Java (bytecode) este tratat ca o zonă de date de către interpretor. Deci firele de excutie sunt create de fapt de către interpretorul Java. La lansarea în execuție a unei aplicații Java este creat și automat un prim fir de execuție, numit firul principal. Acesta poate să creeze alte fire de execuție, care la rândul lor pot crea alte fire, și așa mai departe.

2.1.1. De ce avem nevoie de fire de execuție?

Aplicațiile care utilizează mai multe fire de execuție pot executa în paralel mai multe sarcini. De exemplu, o aplicație care realizează o animație într-o fereastră, iar într-o altă fereastră afișează rezultatul unei interogări de baza de date.

Un program de navigare realizează cel puțin două lucruri în paralel: aduce date din rețea și paralel afișează aceste date.  Firele de execuție facilitează ca programarea să fie mai apropiată de gândirea umană. Omul de obicei se ocupă de mai multe lucruri în același timp. Un profesor în timp ce predă trebuie să fie atent și la studenții care îl ascultă.

Firele de execuție Java oferă o serie de facilități  programatorilor, dar există și o serie de diferențe față de alte pachete pentru fire de execuție. Comparând cu aceste pachete, putem considera că ne oferă mai puțin, dar au și un avantaj, simplitatea. Există și un standard, un pachet de fire de excutie, care poate fi implementat în orice sistem de operare.

Orice pachet Java (de la Sun) este "Thread safe", adică este asigurat că metodele conținute în pachet pot fi apelate simultan  de mai multe fire de execuție.
 

Utilizarea firelor de execuție în Java

1. Creare și lansare. În Java avem două posibilități de a crea un fir de execuție:

Prin definirea unei clase care moștenește de la clasa predefinita Thread (derivă din clasa Thread)

Prin implementarea interfeței Runnable

Clasa Thread este definită în pachetul java.lang având o serie de metode. Principala metodă este metoda run(). Aceasta trebuie să conțină toate activitățile pe care firul trebuie să le execute.

public class Thread extends Object implements Runnable

Clasa Thread este o clasă care are ca și superclasa clasa Object și implementează interfața Runnable. Interfața Runnable declară o singură metodă run() și clasa Thread implementează aceasta. Mașina virtuală Java permite unei aplicații să ruleze mai multe fire de execuție în paralel. Fiecare fir de execuție are o prioritate și fiecare fir poate fi marcat ca și fir demon. În momentul creării unui fir de execuție se setează și proprietățile acestea, adică firul nou creat va avea aceeași prioritate ca și firul părinte și va fi de tip demon numai dacă firul părinte este demon.

Metoda  start() este utilizată pentru lansarea în execuție a unui fir nou creat. Metoda start() se utilizează o singură dată în ciclul de viață al unui fir. Firul se distruge cu metoda destroy(), și aceasta putând fi apelată o singură dată.

Metoda sleep() se apelează cu un argument care reprezintă timpul în milisecunde în care firul de execuție așteaptă(adoarme). sleep() este o metodă statică, se apelează prefixat cu numele clasei. În caz că firul este întrerupt se generează excepția InterruptedException. Deci apelul metodei trebuie făcut într-un context de tratarea acestei excepții.

try{

    Thread.sleep( 1000 )

}

catch ( InterruptedException e ){

    //Codul  de tratarea a excepției

}
Firul poate fi scos din starea de adormire prin apelul metodei interrupt(). Metoda se mai apelează pentru a întrerupe execuția unui fir care este blocat în așteptarea unei operații lungi de intrare/ieșire. Metoda join() se utilizează pentru legarea firelor de execuție. Prin getName() și setName() putem obține sau să setăm numele firului.

Diagrama de clase:

Diagrama de colaborare:

Figura precedentă prezintă proiectul unei aplicații, care crează două fire de execuție și le starteaza, neașteptând terminarea acestora. Firele vor afișa numele lor până când sunt oprite. Firele pot fi oprite cu combinația de taste Ctrl-C. Crearea unui obiect din clasa MyThread nu înseamnă și începerea execuției firului creat. Firul poate fi lansat în execuție prin apelul metodei start(). Metoda start() apelează metoda run(), care execută instrucțiunile proprii firului.

Sursa Java pentru exemplul precedent:

//Source file: MyThread.java

public class MyThread extends Thread
{
   public MyThread()
   {
   }

   public void run()
   {
    while( true )
      try{
           System.out.println(" Se rulează "+getName());
           sleep( 1000 );
      }
      catch( InterruptedException e ){}
   }

   public MyThread(Strâng name)
   {
    super( name );
   }
}

//Source file: Control.java

public class Control
{
   public MyThread threads[];

   public Control()
   {
    threads = new MyThread[ 2 ];
    threads[ 0 ] = new MyThread( "Fir 1");
    threads[ 1 ] = new MyThread( "Fir 2");
    threads[ 0 ].start();
    threads[ 1 ].start();
   }

   public static void main(Strâng[] args)
   {
    Control c = new Control();
   }
}

Diagrama de clase:

Diagrama de colaborare:

Sursa Java:

//Source file: Control.java

public class Control
{
   public MyRunnable objects[];
   public Thread threads[];

   public Control()
   {
    objects = new MyRunnable[ 2 ];
    objects[ 0 ] = new MyRunnable();
    objects[ 1 ] = new MyRunnable();
    threads = new Thread[ 2 ];
    threads[ 0 ] = new Thread(objects[ 0 ]);
    threads[ 1 ] = new Thread(objects[ 1 ]);
    threads[ 0 ].start( );
    threads[ 1 ].start( );
   }

 
   public static void main(Strâng[] args)
   {
    Control c = new Control();
   }
}
 

//Source file: MyRunnable.java

public class MyRunnable implements Runnable
{
   public MyRunnable()
   {
   }

   public void run()
   {
    while( true )
    {
      System.out.println( "Se rulează "+(Thread.currentThread()).getName() );
      try{
       Thread.sleep( 1000 );
      }
      catch( InterruptedException e ){}
     }
   }
}
 

2.2. Legarea firelor de execuție
 

Legarea firelor de execuție permite unui fir să aștepte ca un alt fir să-și termine execuția. De exemplu un fir trebuie să utilizeze date care sunt calculate de un alt fir de execuție, atunci în momentul când are nevoie de aceste date își întrerupe execuția așteptând firul care îi va furniza acestea.  Pentru legarea firelor se utilizează metoda join().  Metoda are două formă de apel:

join( int timp ) parametrul  reprezintă timpul de așteptare (în milisecunde), adică cât se așteaptă pentru terminarea firului,

join() se așteaptă terminarea firului indiferent cât trebuie așteptat

Exemplul următor crează două fire de excutie. Unul dintre fire afișează un text și așteaptă 500 de milisecunde de cinci ori. Celălalt fir își afișează numele după care așteaptă pe celălalt fir că acesta să-și termine execuția.

Diagrama de secventiere:

Sursa Java:

//Source file: MyThread1.java

public class MyThread1 extends Thread
{
   public MyThread1(Strâng name)
   {
    super( name);
   }

   public void run()
   {
     System.out.println(getName() + "îs running");
        for(int i=0;i<5;i++){
         try{
                     sleep( 500 )  ;
            }
            catch( InterruptedException e ){}
            System.out.println(getName()+" writes "+Integer.toString(i));
       }
   }
}

//Source file: MyThread2.java

public class MyThread2 extends Thread
{
   public MyThread1 waitedThread;
 

   public MyThread2(Strâng name, MyThread1 waitedThread)
   {
    super( name );
    this.waitedThread = waitedThread;
   }

   public void run()
   {
     System.out.println(getName()+" waits for Thread "+waitedThread.getName());
     try{
                 waitedThread.join();
     }
     catch( InterruptedException e ){}
     System.out.println(waitedThread.getName()+" has been finished");
     System.out.println(getName()+" has been finished");
   }
}

//Source file: Control.java

public class Control
{

   public static void main(java.lang.Strâng args[])
   {
     MyThread1 thread1 = new MyThread1("First Thread");
     MyThread2 thread2 = new MyThread2("Second Thread",thread1);
     thread1.start();
     thread2.start();
   }
}

2.3. Fire de execuție demoni

Caracteristici:

Sunt fire speciale similare cu procesele demoni.

Realizează anumite activități în fundal (background)

Se distrug automat la terminarea celorlaltor fire de execuție.

Au prioritate de execuție redusă, fiind planificate la CPU când acesta nu rulează alte fire

Colectarea gunoiul în Java se relueza pe un fir demon. Firul poate fi transformat în fir demon prin apelul metodei setDaemon().

Exemplul următor ar trebui să ne arate că firele demoni sunt planificate pentru execuție mai rar decât cele normale.
 

class  MyThread extends Thread{

    public MyThread( Strâng name, boolean îs_Daemon ){

        super(name);

        setDaemon(îs_Daemon);

    }

    public void run(){

      for(int i=0;i<5;i++){

            try{

                sleep( 500 )  ;

            }

            catch( InterruptedException e ){}

            System.out.println(getName() + "se rulează");

      }

    }
    }

    public class Control{
        public static void main( Strâng args[] )
        {
            MyThread t1,t2;
            t1 = new MyThread("Normal", false );
            t2 = new MyThread("Demon ", true  );
            t1.start();
            t2.start();
        }
    }
 
 

2.4. Grupe de fire de execuție

La crearea unui fir nou de execuție, firul nou creat putem să-l adăugăm la un grup de fire de execuție existent, sau putem lăsa în seama interpretorului Java la care grup să-l adauge. În exemplul demonstrativ vom utiliza metoda  yield () pentru a ceda unitatea centrală altui fir de execuție (astfel firul care cedează trece în coada de așteptarea a firelor gata de execuție).

    class MyThread extends Thread{
         MyThread( Strâng nume ){
             super( nume );
         }
         public void run(){
             while( true ){
                 if (isInterrupted() )
                           break;
                 yield();
             }
         }
     }
 

     public class Control{
         static public void main( Strâng args[] ){
             MyThread a, b, c;
             ThreadGroup group;
             // Obținerea unei referințe la grup
             group = Thread.currentThread().getThreadGroup();
             System.out.println(" Nume grup: "+group.getName());
             System.out.println(" Nr. fire active: "+group.activeCount());
             a = new MyThread("Fir 1 ");
             b = new MyThread("Fir 2 ");
             c = new MyThread("Fir 3 ");
             a.start(); b.start(); c.start();
             System.out.println(" Nr. fire active: "+group.activeCount());
             a.interrupt();
             b.interrupt();
             c.interrupt();
         }
     }
 

2.4.1. Stările unui fir de execuție

Fir "rulabil" (Runnable): se ajunge în această stare prin apelul metodei start(). Firul trece în stare de "nerulabil" (Not Runnable) prin apelul metodei sleep() , wait() sau dacă firul se blochează într-o operație de citire. După terminarea așteptării firul revine în starea "rulabil".

Firul ajunge în starea "mort", după ce se termină execuția metodei run() sau dacă se apelează metoda destroy().

Firele sunt planificate pentru execuție la fel ca și procesele, utilizând un algoritm adecvat pentru planificarea lor. Dacă mașina virtuală se rulează pe un sistem de oprare care lucrează cu fire de execuție, atunci s-ar putea ca fiecare fir de execuție creat de către mașina virtuală Java să fie executat pe un fir nativ.

Prioritatea firelor de execuție

Mașina virtuală Java utilizează prioritățile firelor în planificarea firelor pentru execuție. În Java sunt 10 niveluri de prioritate. Avem și trei constante în clasa Thread ce pot fi utilizate:

Thread.MIN_PRIORITY având valoarea 1

Thread.MAX_PRIORITY  având valoarea 10

Thread.NORM_PRIORITY având valoarea 5

Prioritatea firului se setează cu metoda setPriority()

Sincronizarea firelor de execuție.

Fiecare fir de execuție are o viață proprie și nu este interesat de ceea ce fac celelalte fire de execuție. Dacă calculatorul este dotat cu mai multe procesoare, atunci diferitele fire de execuție ale aceluiași proces pot fi planificate pentru execuție pe diferite procesoare. Pentru cel care proiectează aplicația, acest lucru este nesemnificativ, deoarece toate aceste lucruri cad în sarcina mașinii virtuale și nu în sarcina programatorului. Totuși apare o problemă în cazul aplicațiilor care se rulează pe mai multe fire și anume accesul resurselor comune. Ca să nu apară probleme, accesul la resursele utilizate în comun trebuie sincronizat. Sincronizarea se bazează pe conceptul de monitor introdus de către C.A. Hoare. Un monitor este de fapt un lacăt atașat unei resurse pentru a preveni utilizarea resursei în paralel.

Un fir de execuție ocupă un monitor dacă apelează o metodă sincronizată. Dacă un fir ocupă un monitor, un alt fir care încearcă ocuparea aceluiași monitor, este blocat și așteaptă până la eliberarea monitorului.

Oricare obiect, care conține unul sau mai multe metode sincronizate, are și un monitor atașat. Metodele sincronizate se definesc în modul următor:

public synchronized void my_method() {…}

Orice clasă Java are un monitor atașat. Acest monitor se deosebește de monitoarele atașate obiectelor, se utilizează când se apelează metodele statice sincronizate ale clasei.

public static synchronized void my_static_method() {…}

wait() și notify()

Cu ajutorul cuvântului-cheie „synchronized” putem serializa execuția anumitor metode. Metodele wait() și notify() ale clasei Object extind aceasta capabilitate. Utilizând wait() și notify(), un fir de execuție poate elibera monitorul ocupat, așteptând un semnal pentru reocuparea acestuia. Metodele pot fi utilizate doar în metode sincronizate sau în blocuri de instrucțiuni sincronizate. Executând wait() într-un bloc sincronizat, firul eliberează monitorul și adoarme. De obicei firul recurge la această posibilitate când trebuie să aștepte apariția unui eveniment într-o altă parte a aplicației. Mai târziu, când apare evenimentul, firul, în care a apărut evenimentul, apelează notify() pentru a trezi firul adormit. Firul trezit ocupă din nou monitorul și își continua activitatea din punctul de întrerupere.

class MyClass{
    public synchronized void method1(){}
    public synchronized void method2(){}
    public static synchronized void method3(){}
}

MyClass object1 = new MyClass(); // Se atașează un monitor obiect pentru sincronizarea accesului la metodele method1() și method2() pentru firele de execuție al obiectului object1
MyClass object2 = new MyClass(); // Se atașează un monitor obiect pentru sincronizarea accesului la metodele method1() și method2() pentru firele de execuție al obiectului object2

Pentru exemplul precedent se vor crea trei monitoare. Un monitor de clasă, care este responsabil pentru sincronizarea accesului la metoda statică ( metoda clasei) method3() și două monitoare obiect, câte unul pentru fiecare obiect declarat pentru sincronizarea accesului la method1(0 și method2().

Metoda notify() anunță întotdeauna un singur fir de execuție care așteaptă pentru a accesa monitorul. Există și o altă metodă notifyAll() care se utilizează atunci când mai multe fire de execuție concurează pentru  același monitor. În acest caz, fiecare fir este înștiințat și ele vor concura pentru obținerea monitorului. Metodele wait(), notify() și notifyAll() se utilizează doar în metode sincronizate, altfel mediul de execuți aruncă excepția IllegalMonitorStateException. Exemplul următor se compilează fără erori, dar se aruncă aceasta excepție pe parcursul execuției.

public class test{
 public test(){
     try{
          wait();
     }
     catch( InterruptedException e ){}
 }

 public static void main( Strâng args[] ){
  test t = new test();
 }
}

CAPITOLUL II: APLICAȚIE JAVA CU FIRE DE EXTENSIE

În arhiva atașată se află proiectul. Trebuie dezarhivat și apoi deschis cu NetBeans (platforma pe care se dezvolta programe Java). Dacă nu aveti acest program instalat, poate fi downloadat de la adresa http://www.oracle.com/technetwork/java/javase/downloads/index.html , este al 3-lea link de download sub a cărui poză scrie JDK 7u2 + NetBeans Bundle, ce conține JDK și Netbeans. După ce l-ați downloadat, se instaleză mai intai JDK și apoi Platforma NetBeans despre care v-am vorbit. În momentul în care instalați NetBeans o să vă ceară la un moment dat calea către executabilul Java din JDK-ul instalat inițial, executabil care se află la locația unde ați instalat JDK în folderul JDK\bin.

Legarea firelor de execuție 

Legarea firelor de execuție permite unui fir să aștepte ca un alt fir să-și termine execuția. De exemplu un fir trebuie să utilizeze date care sunt calculate de un alt fir de execuție, atunci în momentul când are nevoie de aceste date își întrerupe execuția așteptând firul care îi va furniza acestea.  Pentru legarea firelor se utilizează metoda join().  Metoda are doua forme de apel: 

join( int timp ) parametrul  reprezintă timpul de așteptare (în milisecunde), adică cât se așteaptă pentru terminarea firului,

join() se așteaptă terminarea firului indiferent cât trebuie așteptat

Explicarea proceselor ce au loc în timpul rulării aplicației.

Aplicația conține 3 clase FirExecutie1.java, FirExecutie2.java și Main.java. 

Aplicația următoare crează, și pornește două fire de excuție, Fir_Executie_1 și Fir_execuție_2 în clasa Main.java. 

La rularea programului se intră în Fir_Executie_1, se afișează mesajul "Fir_Executie_1 rulează !". 

Se intră apoi în Fir_Executie_2 care are nevoie de 3 variabile calculate de Fir_Executie_1, acestea nefiind calculate încă, intră în starea sleep pentru 500 de milisecunde și afișează mesajul "Fir_Executie_2 așteaptă firul de execuție Fir_Executie_1". 

În acel interval de timp în care Fir_Executie_2 este în sleep, Fir_Executie_1 calculează valorile necesare (suma, diferența și produs), după care este terminat. 

Aceste valori sunt preluate de Fir_Executie_2 după ce iese din starea sleep și sunt afișate.

Este terminat apoi și Fir_Executie_2.

/*

* To change this template, choose Tools | Templates

* and open the template in the editor.

*/

package threads;

/**

*

* @author Numele autorului

*/

public class FirExecutie1 extends Thread{

int a = 7;

int b = 3;

public int suma = 0;

public int diferenta = 0;

public int produs = 1;

public FirExecutie1(String name) {

super(name);

}

@Override

public void run() {

System.out.println(getName() + " ruleaza !");

for(int i=0;i<3;i++){

switch(i){

case 0:

suma = a + b;

break;

case 1:

diferenta = a – b;

break;

case 2:

produs = a * b;

break;

}

}

}

}

/*

* To change this template, choose Tools | Templates

* and open the template in the editor.

*/

package threads;

/**

*

* @author Numele autorului

*/

public class FirExecutie2 extends Thread{

public FirExecutie1 firAsteptat;

public int suma;

public int diferenta;

public int produs;

public FirExecutie2(String name, FirExecutie1 firAsteptat){

super(name);

this.firAsteptat = firAsteptat;

}

@Override

public void run(){

System.out.println(getName()+" asteapta firul de executie "+firAsteptat.getName());

try{

sleep(500) ;

}catch( InterruptedException e ){}

try{

firAsteptat.join();

}catch( InterruptedException e ){}

System.out.println(firAsteptat.getName()+" calculeaza valorile necesare pentru " + getName() + " si este terminat");

System.out.println(getName()+" Afiseaza valorile calculate de " + firAsteptat.getName());

suma = firAsteptat.suma;

diferenta = firAsteptat.diferenta;

produs = firAsteptat.produs;

System.out.println("suma = " + suma);

System.out.println("diferenta = " + diferenta);

System.out.println("produs = " + produs);

System.out.println(getName()+" s-a terminat");

}

}

/*

* To change this template, choose Tools | Templates

* and open the template in the editor.

*/

package threads;

/**

*

* @author Numele autorului

*/

public class Main {

/**

* @param args the command line arguments

*/

public static void main(String[] args) {

FirExecutie1 fir1 = new FirExecutie1("Fir_Executie_1");

FirExecutie2 fir2 = new FirExecutie2("Fir_Executie_2",fir1);

fir1.start();

fir2.start();

}

}

CONCLUZII

Java reprezintă în momentul de față nu numai un simplu limbaj de programare ci însumează o serie de tehnologii ce pot fi folosite pentru a crea aplicații complexe structurate pe mai multe nivele și care să implice resurse variate.

JavaScript a fost dezvoltat prima dată de către firma Netscape, cu numele de Live Script, un limbaj de script care extindea capacitatile HTML, oferă o alternativă parțială la utilizarea unui număr mare de scripturi CGI pentru prelucrarea informațiilor din formulare și care adaugă dinamism în paginile web.

După lansarea limbajului Java, Netscape a început să lucreze cu firma Sun, cu scopul de a crea un limbaj de script, cu o sintaxă și semantică asemănătoare cu a limbajului Java, și din motive de marketing numele noului limbaj de script a fost schimbat în "JavaScript".

În zilele noastre, referitor la acest limbaj, oamenii care ăl cunosc au foarte multe avantaje. În primul rând găsirea unui loc de muncă este mult mai ușor. De asemenea partea materială este mult mai avantajoasă decât multe dintre meseriile existente.

BIBLIOGRAFIE

Albeanu Gr., Algoritmi și limbaje de programare, Universitatea “Spiru Haret”, Ed. Romania de Mâine, București, 2000

Cioata Monica – "Java si JDBC", PC Report – 1/1998;

Costinescu Bogdan – "Java si tehnologia client-server", PC Report – 3/1997;

Evnull David – "Java under UNIX", PC-PRO, Sept.1997;

Rotaru Eugen – "Limbajul Java", Computer Press Agora, Tg.Mures, 1996;

Tanasa Stefan, Cristian Olaru, Stefan Andrei, "Java de la 0 la expert", Polirom, 2003.

Somnea D., Inițiere în JavaScript și tehnologii Netscape, Ed. Tehnica, 1998

C. Frasinaru – Curs practic de Java,

www.java.net

www.wikipedia.org;

www.java.com;

javaalmanac.com – Exemple de cod

Similar Posts

  • Injectivitate

    CAPITOLUL I NOȚIUNI GENERALE DE TEORIA MODULELOR MODULE , EPIMORFISME ȘI MONOMORFISME INELE DE ENDOMORFISME MODULE ESENȚIALE ȘI SUPERFLUE SUMANZI DIRECȚI SUME ȘI PRODUSE DIRECTE DE MODULE GENERATORI ȘI COGENERATORI TRASA ȘI REJECTUL SOCLUL ȘI RADICALUL MODULE FINIT GENERATE ȘI COGENERATE INELE SEMISIMPLE INELE DE BIENDOMORFISME ALE SUMELOR DIRECTE RADICALUL UNUI INEL INELE LOCALE CAPITOLUL…

  • Elemente Software Si Hardware Folosite In Realizarea Aplicatiei Fitness

    CUPRINS INTRODUCERE CAPITOLUL I 1.1. ISTORIA FITNESS-ULUI 1.2. ISTORIA APARATELOR DE FITNESS CAPITOLUL II – EXERCIȚIILE FIZICE ȘI PULSUL CAPITOLUL III – ELEMENTE SOFTWARE ȘI HARDWARE FOLOSITE ÎN REALIZAREA APLICAȚIEI FITNESS 3.1. VISUAL STUDIO 3.2. C# ȘI VISUAL C# 3.3. LEGO TEHNIC 3.4. SOLID EDGE 3.5. ARDUINO 3.6. SERVOMOTOARE 3.6.1. Generalități 3.6.2. Funcționarea și controlarea…

  • Portal Băile Felix

    Cuprins 1.Introducere…………………………………………………………………………………..4 2. Fundamentare teoretica……………………………………………………………………..6 2.1 Baze de date .……………………………………………………………………………7 2.1.1 Tipuri de date în MySQL…………………………………………………………7 2.1.2 Crearea unei tabele în baza de date……………………………………………….7 2.1.3 Inserarea datelor în baza de date………………………………………………….7 2.1.4 Modificarea tabelelor……………………………………………………………..8 2.1.5 Ștergerea de înregistrări din baza de date…………………………………………8 2.1.7 Ștergerea unei baze de date……………………………………………………….8 2.2 Aplicatii web……………………………………………………………………………8 3. Tehnologii utilizate…………………………………………………………………………11 3.1…

  • Stocarea Informatiei In Memoria de Lunga Si de Scurta Durata. Mecanisme Biologice de Stocare Si Gestionare a Cunoasterii

    Rezumat Introducere Capitolul 1 Aspecte teoretice 1.1 Noțiuni introductive Procesele și formele memoriei Caracterizarea psihologică a reprezentării în memorie 1.4. Calitățile reprezentărilor 1.5. Clasificarea reprezentărilor Capitolul 2 Informatica psihologică Măsurarea în psihologie 2.2Psihometria 2.3 Caracteristici psihologice ale mediului internet Capitolul 3 Dependența de internet și repercusiunile acesteia.Studiu de caz Concluzii Bibliografie Omul, pe lângă multe…

  • Proiectarea Si Implementarea Unei Retele Locale Si a Unei Aplicatii de Contorizare a Activitatii Retelei

    PROIECTAREA ȘI IMPLEMENTAREA UNEI REȚELE LOCALE ȘI A UNEI APLICAȚII DE CONTORIZARE A ACTIVITĂȚII REȚELEI Cuprins Cap.1 STUDIUL ȘI ANALIZA SISTEMULUI EXISTENT 1.1 1.2 Activitățile desfășurate în unitatea economică (caracteristicile generale ale sistemului economic din unitate) 1.3 Studiul sistemului de conducere. Studiul sistemului condus 1.4 Studiul sistemului informațional 1.4.1 1.4.2 Aria de cuprindere (locul) circuitului…

  • Proiect Informatic Stocuri

    Cuprins Cap.I Introducere……………………………………………………………………….2 Motivatie si metode stiintifice folosite………………………………………………2 Elemente teoretice funfamentale……………………………………………………2 Probleme teoretice…………………………………………………………………..4 Cadru legislativ..…………………………………………………………………….5 Cap.II Studiu de caz…………………………………………………………………….6 2.1 Prezentarea Societății Comerciale S.C. RO-STAR S.A…………………………..6 2.2Evaluarea elementelor de active si pasiv…………………………………………..11 2.3 Valorificarea informatiei contabile in managementul financiar contabil prin creerea unui sistem suport …………………………………………………………….14 2.4 Audit sistem informatic…………………………………………………………….14 2.5 Aplicatie informatica……………………………………………………………….19 Cap.III Concluzii……………………………………………………………………….38…