Sunteți pe pagina 1din 15

6.1.

Interfee Java

- interfeele Java abstractizeaz complet metodele unei clase


(interfaa clasei) fa de orice implementare;
- folosind cuvntul rezervat interface (n loc de class) specificm
ce poate face o clas i nu cum realizeaz clasa acel lucru.
6.1.1. Definirea unei interfee

- forma general a definirii unei interfee Java este


interface nume {
tipRezultat1 numeMetoda1(listaParametri1);
- - -
tipRezultatn numeMetodan(listaParametrin);
tipVariabilaFinala1 numeVariabilaFinala1 = valoare1;
- - -
tipVariabilaFinalak numeVariabilaFinalak = valoarek;
}

-modificatorul unei interfee este public sau abstract (implicit)

6.1.2. Implementarea interfeelor

- odat ce o interfa a fost definit, una sau mai multe clase pot s ofere o
implementare a interfeei;
-pentru a implementa o interfa, o clas trebuie s includ cuvntul rezervat
implements n antetul definiiei sale:

class NumeClasa[ extends ClasaSuperioara ]


implements numeInterfata1 [ , numeInterfata2 . . .] {
//dup care s defineasc toate metodele declarate de
//interfa; de asemenea, se impune ca toate metodele
//interfeelor s fie declarate public.

Exemplu
public interface Runner{
int L1=50;
int L2=100
public void run();
public void speedUp();
}

1
6.1.3. Apelul metodelor prin variabile referine la interfee

Deoarece metodele unei interfee sunt implementate de o clas, evident c le putem


apela prin variabile referin la clasa care implementeaz interfaa.

Java trateaz interfeele ca i clase pur abstracte. Astfel:


putem s definim variabile de tip interfa (referine la interfa);
o variabil interfa poate referi o instan a unei clase ce implementeaz interfaa;
dac o variabil interfa refer o instan care implementeaz interfaa atunci la
apelul unei metode din interfa se va apela metoda instanei (apel conform
obiectului referit i nu conform referinei ca i la redefinirea metodelor n cazul
motenirii).

Exemplu Fisierul TestInterfaces.java

interface Reader{
public void read();
}
interface Writer{
public void write();
}
interface Thinker{
public void think();
}
interface Professor extends Reader,Writer{
int MAX_MARK=10;
int MIN_MARK=1;
public void appreciate();
}
interface Diver {
int h=10;
public void dive();
}

class Swimmer implements Diver{


static final int L=50;
public void swim(){
System.out.println("Swim " +L+" meters");
}
public void dive(){
System.out.println("Dive from " +h+" meters");
}
}

2
class SwimTeacher extends Swimmer implements Professor, Thinker{
public void read(){
System.out.println("Read \"Gazeta Sporturilor\"..");
}
public void write(){
System.out.println("Write sports papers");
}
public void appreciate(){
System.out.println("You are smart.. You get "+MAX_MARK);
}
public void think(){
System.out.println("I can teach you better swimming..");
}
}

class Programmer implements Reader, Writer, Thinker{


public void read(){
System.out.println("Read Java tutorial..");
}
public void write(){
System.out.println("Write OOP soft.. ");
}
public void think(){
System.out.println("Java is the best language..");
}
}

public class TestInterfaces {


public static void whatHeRead(Reader r){
r.read();
}
public static void whatHeWrite(Writer w){
w.write();
}
public static void whatHeThink(Thinker t){
t.think();
}
public static void main(String arg[]){
SwimTeacher t=new SwimTeacher();
Programmer p=new Programmer();
whatHeRead(t);
whatHeWrite(t);
whatHeThink(t);
whatHeRead(p);
whatHeWrite(p);
whatHeThink(p);
}
}

3
6.2. Thread-uri Java

6.2.1. Preliminarii

- n prezent, tendinele n programarea concurent utilizeaz n loc de


proces conceptul de thread;

- multithreding-ul reprezint proprietatea unui program de a conine


mai multe secvene de cod care se execut aparent simultan; o astfel
de secven de cod se numete thread sau fir de execuie;
multithreding-ul este o extensie a conceptului de multitasking;

- pachetul java.lang ofer clasa Thread; aceasta, mpreun cu unele


metode motenite de la clasa Object, permit crearea, execuia,
controlul i sincronizarea thread-urilor;

- este cunoscut faptul c operarea multithreading d mult btaie de


cap programatorilor C i C++; programatorii trebuie s-i
implementeze mecanisme proprii de blocare a unor seciuni critice i
de partajare a unor resurse critice; primitivele furnizate de Java
reduc esenial acest efort;

- n particular, sincronizarea se bazeaz pe conceptul de monitor.

4
6.2.2. Metodele clasei Object

Metodele wait()
Pun obiectul n ateptare pn la apariia unui eveniment. Ultimele dou forme indic o
durat maxim de ateptare, fie numai n milisecunde, fie n milisecunde plus
nanosecunde.
Metodele notify() i notifyAll()
Sunt duale metodelor wait(), ele anun alte obiecte apariia unui eveniment.

Metoda getClass()
ntoarce clasa din care s-a instaniat obiectul apelant al metodei.

Metoda equals()
Ofer, prin suprascriere n subclase, posibilitatea de a se defini ce nseamn egalitatea a
dou obiecte din clasa respectiv. Implementarea acestei metode trebuie s respecte,
pentru orice referiri nenule x, y, z, urmtoarele condiii:
reflexivitate, adic x.equals(x) reflexivitate, adic x.equals(x) trebuie s ntoarc true;
simetrie, adic x.equals(y) este true dac i numai dac y.equals(x) este true;
tranzitivitate, adic x.equals(y) este true i y.equals(z) este true implic x.equals(z)
este true;
consisten, adic datele utilizate n metoda equals s nu modifice relaia ntre dou
obiecte; deci, pentru dou obiecte x i y, apelurile multiple x.equals(y) trebuie s
ntoarc mereu fie true, fie false;
referina null: x.equals(null) s fie mereu false.

Metoda finalize()
Poate fi suprascris n subclase i ea conine aciunile pe care componenta garbage
collecter din JVM le va executa imediat nainte de a distruge un obiect. Trebuie
remarcat faptul c programul utilizator nu poate stabili cu exactitate momentul i
ordinea de execuie a metodelor finalize legate de obiecte expirate.

Metoda toString()
ntoarce reprezentarea textual a obiectului. Este util uneori n activitatea de depanare.
Se recomand suprascrierea ei dac se intenioneaz a fi utilizat.

5
6.2.3. Clasa Thread

n acelai stil ca i n seciunea precedent, prezentm principalele metode ale clasei


Thread.
Dac se specific n constructor un obiect tinta, atunci corpul threadului (corpul
metodei run) este ataat acestui obiect. Dac nu se specific, atunci corpul este ataat
thread-ului nou creat.
Prin constructor, sau mai trziu folosind metoda setName(), se poate atribui thread-
ului un nume. Dac nu se specific alt valoare, atunci numele implicit va fi Thread-
+n, unde n este un ntreg. Metoda getName() ntoarce numele curent al thread-ului.

Metoda start()
Lanseaz n execuie noul thread. Din acest moment, execuia programului este
controlat de (cel puin) dou thread-uri: pe de o parte funcioneaz thread-ul curent -
cel care execut start(), iar pe de alt parte se lanseaz n execuie noul thread, ale
crui instruciuni sunt precizate n metoda run().

Metoda run()
Conine corpul efectiv al thread-ului. ntreaga activitate curent a noului thread trebuie
descris prin suprascrierea acestei metode.

Metodele sleep()
Pun thread-ul curent n ateptare un anumit interval de timp.

Metodele join()
Ateapt ca obiectul thread care le apeleaz s moar. Ultimele dou forme limiteaz
timpul maxim de ateptare.

Metoda yield()
Cedeaz controlul de la obiectul thread la planificatorul JVM, pentru a permite unui alt
thread (green) s ruleze.

Metoda interrupt()
Trimite o ntrerupere obiectului thread care o invoc.

6
Metodele interrupted() i isInterrupted()
Testeaz dac thread-ul apelant a fost ntrerupt sau nu. Metoda interrupted() modific
statutul de ntrerupt, aa c la un dublu apel al ei starea thread-ului revine la vechea ei
form. Metoda isInterrupted nu modific aceast stare.

Metoda isAlive()
Rspunde dac obiectul thread apelant este n via sau nu.

Metoda activeCount()
ntoarce numrul de thread-uri active din grupul curent. Metoda currentThread()
ntoarce numrul thread-ului curent. Metoda enumerate() ntoarce n tabloul t thread-
urile membre ale grupului curent i ale celor din subgrupuri. Metoda
getThreadGroup() ntoarce grupul curent de thread-uri. Metoda dumpStack()
afieaz la ieirea standard stiva curent de thread-uri.

Metodele stop(), suspend() i resume()


Au fost definite n primele versiuni Java. Ulterior s-a dovedit c folosirea lor poate
conduce, n cazul unei proiectri neatente a programului, la impas i din aceast cauz
ncepnd cu versiunea 1.2 au fost declarate deprecated, motiv pentru care nici noi nu
le vom acorda prea mare atenie. Metoda stop() provoac oprirea execuiei unui thread.
Metoda suspend() suspend temporar execuia thread-ului, reluarea i continuarea
execuiei fcndu-se cu metoda resume().

6.2.4. Operaii asupra thread-urilor Java; creare, terminare


6.2.4.1. Crearea unui thread
Crearea unui thread folosind Java API se poate face n dou moduri:
implementnd o clas derivat din clasa predefinit Thread, clas care face parte din
pachetul java.lang i ca urmare este importat automat n orice program Java;
definind o clas care implementeaz interfaa Runnable.

Primul mod const n a declara o clas ca subclas a clasei Thread. n interiorul


acesteia se redefinete metoda run(), metod care conine corpul de instruciuni ale
thread-ului. Dup aceea, se poate defini i instania noua subclas. Schematic, crearea
se face conform modelului urmtor:

7
class ThreadPropriu extend Thread {
// - - - datele subclasei - - -
ThreadPropriu (/* parametrii constructorului */ ) {
// - - - descrierea constructorului
}
public void run() {
// - - - defineste corpul thread-ului ThreadPropriu - - -
}
}

Exemplu: fisierul FirstThread.java


class MyThread exdends Thread{
public void run(){
int nrPasi=5;
System.out.println(run are + nrPasi+de realizat);
for(int i=1;i<=nrPasi;i++)
System.out.println(Pasul:+i);
System.out.println(run si-a terminat sarcina);
}
}
public class FirstThread{
public static void main(String args[]){
System.out.println(Crearea thread);
MyThread thread = myThread();
System.out.println(Start thread);
thread.start();
System.out.println(Revenire in main);
}
}
Execuia:
Crearea thread
Start thread
Revenire in main
run are 5 pasi de realizat
Pasul:1
Pasul:2
Pasul:3
Pasul:4
Pasul:5
run si-a terminat sarcina

8
A doua metod const n implementarea clasei Runnable. Aceast interfa conine o
unic metod, i anume metoda run:

interface Runnable {
public void run ();
}

Astfel, o clas care implementeaz interfaa Runnable, evit descendena din clasa
standard Thread. Instanele acestei clase sunt create ca obiecte active, n thread-uri
diferite de thread-ul curent. Schematic, acest mod de creare a unui thread apare
aproape ca mai sus, cu excepia primei linii:
class ThreadPropriu - - - implements Runnable {
// - - - datele subclasei - - -
ThreadPropriu ( /* parametrii constructorului */ ) {
// - - - descrierea constructorului
}
public void run() {
// - - - defineste corpul thread-ului ThreadPropriu - - -
}
}

Dup definirea clasei ThreadPropriu, indiferent de modalitate, urmeaz crearea


thread-ului i lansarea n execuie:
ThreadPropriu thr = new ThreadPropriu(- - -);
thr.start();

Mai nti se creeaz obiectul thread, dup care se lanseaz metoda start() pentru
efectuarea iniializrilor.

Execuia curent a unui thread const n execuia metodei run(), similar din acest
punct de vedere cu funcia main() a unui program standalone. Spre deosebire de
main(), metoda run() nu primete argumente din linia de comand. Eventualii
parametri pot fi transmii thread-ului prin constructor, variabile statice sau prin alte alte
metode stabilite de programator.

9
Exemplu: fiierul FirstRunnable.java
class Display{
public void display(String message){
System.out.println(message);
}
}

class MyRunnable extends Display implements Runnable{


public void run(){
int nrPasi=3;
display(run are + nrPasi+de realizat);
for(int i=1;i<=nrPasi;i++)
System.out.println(Pasul:+i);
System.out.println(run si-a terminat sarcina);
}
}

public class FirstRunnable{


public static void main(String args[]){
System.out.println(Create the runnable object);
MyRunnuble myRunnable = new MyRunnable();
System.out.println(Create the thread);
Thread thread = new Thread(myRunnable);
System.out.println(Start thread);
thread.start();
System.out.println(revenire in main);
}
}

Execuia:
Create the runnable object
Crearea thread
Start thread
Revenire in main
run are 3 pasi de realizat
Pasul:1
Pasul:2
Pasul:3
run si-a terminat sarcina

10
Terminarea unui thread
JVM execut un thread, precum i pe cele pe care acesta le creeaz, pn cnd apare
una dintre urmtoarele situaii:
Este apelat metoda exit() a clasei Runtime, iar managerul de securitate a permis
ndeplinirea cu succes a acestui apel.
Toate thread-urile care nu sunt de tipul daemon s-au terminat, fie prin ntoarcerea
din apelul metodei run(), fie printr-un apel al metodei stop() din partea altui thread,
fie prin trimiterea unei ntreruperi (interrupt()) din partea altui thread.
S-a invocat metoda stop() a obiectului thread (metod depit).

La terminarea unui thread, resursele specifice acestuia sunt eliberate. Obiectul thread
nu va fi ters din memorie de ctre garbage collector dect la dereferenierea manual a
instanei (atribuirea valorii null pentru referin) sau la terminarea programului.

6.2.4.2. Ateptarea terminrii unui thread


Dac se dorete ateptarea terminrii unui thread, se poate folosi metoda join() a
obiectului thread dup care se ateapt. Thread-ul a crui terminare se ateapt nu este
afectat de acest apel. Funcia join() are acelai efect ca i combinaia de metode sleep()
i isAlive().

Apelul this.join() nseamn wait forever pentru c thread-ul curent nu se va


termina niciodat datorit acestui apel de ateptare. Funcia join() apelat pentru un
thread, care nu i-a nceput execuia sau s-a terminat, returneaz fr s atepte.

6.2.5. Sincronizarea thread-urilor Java


6.2.5.1. Conceptul de monitor Java; synchronized
Mecanismele de sincronizare ale thread-urilor Java au la baz conceptual de monitor.
Obiectele monitor aplic principiul excluderii mutual pentru grupul de proceduri
sincronizate. Excluderea mutual la datele partajate se obine prin accesul serializat al
thread-urilor: "un thread odat".

11
Limbajul Java a implementat noiunea de monitor ca un element asociat fiecrui obiect
Java. Utilizarea direct a monitoarelor este permis prin intermediul cuvntului
rezervat synchronized aplicat funciilor membre sau unor seciuni de cod din interiorul
metodelor.

Ca urmare, pentru a proteja o seciune critic, se poate declara sincronizat


a) o metod complet, sau
b) un bloc (o secven de instruciuni) dintr-o metod.

n prima situaie, mecanismul de sincronizare este asociat obiectului curent (mai corect
spus, monitorului acestuia) iar n al doilea caz, se poate alege obiectul de sincronizare,
de exemplu, un obiect declarat static n clasa curent sau din nou, obiectul curent.

Ca regul, nu se alege ca obiect de sincronizare un obiect a crui valoare se modific n


interiorul blocului. Deci, pentru un obiect, statutul de monitor se poate obine fie pe
ntreaga durat a execuiei unei metode fie pe durata execuiei unei anumite secvene
de instruciuni.

Schematic, aplicarea declaraiilor synchronized se face dup una din urmtoarele dou
scheme:
public synchronized numeMetoda ( ){ - - - }
sau
synchronized (obiect) { bloc (secven de instruciuni) }

n prima situaie, un apel obiect.numemetoda() face ca obiect s primeasc statutul


de monitor. Deci orice apel obiect.altaMetoda(), unde altaMetoda este i ea
sincronizat, va rmne n starea de ateptare a exclusivitii pn cnd apelul
obiect.numemetoda() i ncheie activitatea.

n a doua situaie, se confer obiectului obiect statutul de monitor pn la terminarea


secvenei de instruciuni specificat ntre acoladele instruciunii synchronized. Trebuie
remarcat faptul c obiectul argument al instruciunii synchronized nu este obligatoriu
s coincid cu obiectul curent.

12
n legtur cu metodele/seciunile de program sincronizate trebuie fcute urmtoarele
precizri:
Cnd este apelat o procedur sincronizat (care conine atributul synchronized)
pentru un obiect, se verific monitorul asociat obiectului.

Dac exist alte metode sincronizate care se execut, prima metod se va bloca,
pn la terminarea lor.
Deci se pot executa n paralel: o singura metod sincronizat
cu mai multe metode nesincronizate.

Metode sincronizate statice


n cazurile precedente de sincronizare, am precizat c acest mecanism este posibil prin
obinerea monitorului asociat obiectului curent de sincronizare.

Metodele statice nu sunt particulare unei anumite instane a clasei curente, motiv
pentru care la sincronizarea acestora se folosete un obiect denumit class lock. i n
acest caz, sistemul este destul de inteligent ca s suporte blocri imbricate, deci dac o
metod static sincronizat este apelat din interiorul altei metode statice sincronizate,
nu mai este cerut obiectul class lock asociat.

6.2.5.2. Mecanismul wait/notify


Un thread care are exclusivitatea asupra unui obiect cu statut de monitor poate ceda
temporar exclusivitatea. Aceast cedare temporar se face apelnd metoda wait(). Ca
efect, este cedat exclusivitatea asupra obiectului, iar thread-ul curent i oprete
temporar execuia instruciunilor lui, adic trece n starea Waiting.

Reluarea exclusivitii cedate de ctre un thread care a executat un wait are loc atunci
cnd thread-ul respectiv se trezete ca urmare a receptrii unui anun trimis de ctre
un alt thread activ care execut una dintre metodele notify() sau notifyAll(). n urma
acestui eveniment, thread-ul i recapt exclusivitatea cedat anterior i i continu
execuia instruciunilor de unde i-a oprit-o anterior (dup apelul wait()).

Anunul efectuat prin notify() se adreseaz tuturor thread-urilor care sunt n starea
Waiting, dar numai unul dintre ele i va relua activitatea, celelalte vor rmne n
continuare n starea Waiting. n schimb, anunul efectuat prin notifyAll() este
recepionat de ctre toate thread-urile aflate n starea Waiting. n consecin toate
thread-urile ies din aceast stare i i continua activitatea.

13
Este posibil ca un thread s solicite intrarea n starea Waiting doar pentru un interval
limitat de timp. n acest caz el va specifica n apelul wait durata maxim pe care o
admite.
De asemenea, un thread poate iei din starea Waiting dac un alt thread apeleaz
metoda interrupt() a thread-ului aflat n starea Waiting. n acest caz execuia lui se reia
cu secvena catch ce intercepteaz ntreruperea.

n sumar, prezentm scenariul de comunicare ntre thread-uri, folosind funciile wait i


notify:
1. Un thread are nevoie n timpul execuiei de o condiie despre care presupune c va fi
realizat n alt thread.
2. Primul thread ateapt realizarea condiiei cu ajutorul metodei wait(), oferind astfel
fiecrui thread suport pentru acest mechanism de comunicare.
3. Thread-ul care realizeaz condiia n timpul execuiei, anun acest lucru unui thread
care ateapt, prin apelul funciei notify().

Metodele wait() i notify() trebuie apelate din interiorul unei metode sau bloc
sincronizat, pentru a preveni eventuale rezultate incorecte, generate de lipsa
sincronizrii.

nainte de a intra n ateptare folosind wait(), thread-ul curent elibereaz obiectul de


sincronizare blocat i-l obine din nou cnd thread-ul este anunat c a fost realizat
condiia ateptat.

Metodele wait() i notify() sunt metode native, scrise n C i nu este posibil


reimplementarea lor folosind numai limbajul Java.

Mai facem cteva precizri n legtur cu comportarea mecanismului wait/notify:


Dac notify() este apelat dintr-un thread, dar nu este nici un thread care s atepte,
atunci metoda notify() returneaz fr nici o eroare.
Funcia wait() elibereaz obiectul de sincronizare la intrarea n ateptare i l reobine
la recepionarea unei notificri. Sistemul asigur atomicitatea acestor operaii critice.
Dac exist mai multe thread-uri care ateapt o anumit condiie, nu se poate tii
care thread primete notificarea dup apelul funciei notify(). Acest lucru depinde de
JVM i de mecansimul de planificare a thread-urilor.
Dac se dorete apelul funciilor wait() i notify() din metode statice, atunci se
declar n interiorul clasei un obiect de sincronizare static, iar funciile wait() i
notify() se vor apela pentru acest obiect static.

14
Diferena esenial dintre funciile wait i sleep const n faptul c metoda sleep nu este
obligatoriu s fie apelat dintr-un bloc sincronizat i nu implic blocarea sau
deblocarea unui obiect de sincronizare.

15