Académique Documents
Professionnel Documents
Culture Documents
1. Crearea unui task prin implementarea din clasa Runnable. Clasa LiftOff implementeaza Runnable.
In main, se creaza un obiect de tipul LiftOff task-ul se va executa intr-un fir de executie.
package concurenta1;
class LiftOff implements Runnable {
//fiecare obiect din clasa LiftOff
//va fi un task ce poate fi rulat pe un fir de executie
protected int countDown = 10; // Default
private static int taskCount = 0; //cont task-uri
private final int id = taskCount++;//contor nr obiecte din LiftOff
public LiftOff() {
}
public LiftOff(int countDown) {
this.countDown = countDown;
}
public String status() { //status-ul task-ului
return "#" + id + "(" + (countDown > 0 ? countDown : "Liftoff!") + "), ";
//constructia ? <=> id (countDown>0) concateneaza LiftOff
}
//metoda run() - implementata in interfata Runnable
public void run() { //lanseaza executia task-ului
while (countDown-- > 0) {
System.out.print(status());
Thread.yield(); //mesaj catre scheduler-ul de task-uri
//ca mare parte din ciclu s-a executat
//si se poate ocupa de alte task-uri intre timp
//este optional
}
}
}
package concurenta1;
public class MainThread {
public static void main(String[] args) {
LiftOff launch = new LiftOff();
launch.run(); //nu se creeaza fir nou de executie ci se ruleaza task-ul in firul prinicipal
}
}
Pentru a rula task-ul LiftOff intr-un fir de executie parallel utilizarea clasei Thread pentru a crea un
fir de execuie:
package concurenta1;
public class BasicThreads {
public static void main(String[] args) {
//task-ul este executat intr-un nou Thread
//clasa Thread asteapta in constructor un obiect
//ce implementeaza interfata Runnable
Thread t = new Thread(new LiftOff());
t.start();//se lanseaza executia in nou fir de executie: LiftOff.run()
System.out.println("Waiting for LiftOff");
}
}
Atentie la momentul in care este afisat mesajul din main (inainte sau dupa executia run)
package concurenta1;
public class MoreThreads {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) { //deschiderea a 5 fire
new Thread(new LiftOff()).start();
}
System.out.println("Waiting for LiftOff");
}
}
package concurenta1;
import java.util.concurrent.*;
public class SingleThreadExecutor {
public static void main(String[] args) {
ExecutorService exec = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
exec.execute(new LiftOff());
}
System.out.println("Waiting for executor to terminate!");
exec.shutdown();
}
}
package concurenta1;
public class EvenGenerator extends IntGenerator {
private int currentEvenValue = 0;
public int next() { //next trebuie intotdeauna sa returneze un numar par
//este posibil ca un task deschis sa apeleze next() si sa modifice
//valoarea currentEvenValue
//imediat dupa ce un alt task a facut prima operatie de increment
//=> obiectul poate fi intr-o stare incorecta iar next() poate returna
//un nr impar
// aici trebuie inserat cuvantul cheie synchronized pentru serializa accesul la resursa
// intrebare: care este resursa critica?
++currentEvenValue; // Danger point here!
++currentEvenValue;
return currentEvenValue;
}
public static void main(String[] args) {
EvenChecker.test(new EvenGenerator());
}
}
Pentru a rezolva problema accesului concurrent la obiectul de tip IntGenerator fara ca nici un fir
de executie sa poata sa acceseze o stare incorecta a obiectului Intgenerator. (nu se stie cand
un Thread este lansat de catre scheduller).
Rezolvare: blocarea resursei de catre primul thread care o acceseaza (aceasta devenind
inaccesibila celorlalte thread-uri pana cand procesul care a blocat-o o va elibera)
Sincronizarea in EvenGenerator pentru rezolvarea problemei de mai sus:
package concurenta1;
public class SynchronizedEvenGenerator extends IntGenerator {
private int currentEvenValue = 0;
//prin synchronized - primul task care apeleaza
//metoda next() va bloca zona de memorie aferenta
//atributului currentEvenValue - nici un thread nu va \
//putea accesa zona currentValue - pana cand nu va fi eliberata
public synchronized int next() {
++currentEvenValue;
Thread.yield(); // Cause failure faster
++currentEvenValue;
/*if (currentEvenValue%2!=0) //verificare ca se genereaza doar numere pare
System.err.println(currentEvenValue+" is not even!"); */
return currentEvenValue;
}
public static void main(String[] args) {
EvenChecker.test(new SynchronizedEvenGenerator());
}
}
}
}
public static void main(String[] args) {
EvenChecker.test(new MutexEvenGenerator());
}
} ///:~
public PairValuesNotEqualException() {
super("Pair values not equal: " + Pair.this);
}
}
// Arbitrary invariant -- both variables must be equal:
public void checkState() { //ambele valori x si y trebuie sa fie egale
if (x != y) {
throw new PairValuesNotEqualException(); //daca x nu e egal cu y =>exceptie
}
}
}
// Protect a Pair inside a thread-safe class:
abstract class PairManager {
AtomicInteger checkCounter = new AtomicInteger(0);
//!!!obiectul atribut p este partajat de mai multe
//fire de executie
//obiectul p trebuie intodeauna sa isi pastreze starea
//de consistenta: adica p.x==p.y
protected Pair p = new Pair();
//lista sincronizata
private List<Pair> storage = Collections.synchronizedList(new ArrayList<Pair>());
//metoda sincronizata pentru a pastra starea obiectului corecta - valorile x si y egale
// atentie: se returneaza o copie a obiectului p
// intrebare: de ce trebuie synchronized?
public synchronized Pair getPair() {
// Make a copy to keep the original safe:
return new Pair(p.getX(), p.getY());
}
// Assume this is a time consuming operation
protected void store(Pair p) {
storage.add(p);//adaugarea perechii la storage
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException ignore) {
}
}
public abstract void increment();
}
// Synchronize the entire method:
class PairManager1 extends PairManager {
//metoda sincronizata pentru a ne asigura
//ca cele doua perechi x si y sa ramana egale
//astfel incat nici un alt fir de executie
//sa nu poata modifica in paralel pe x si y din p
}
//un alt thread monitorizeaza in paralel
//daca perechea trimisa in constructor este in stare valida
public void run() {
while (true) {
pm.checkCounter.incrementAndGet(); //de cate ori s-a facut verificarea
pm.getPair().checkState(); //verificarea starii perechii pm
}
}
}
public class CriticalSection {
// Test the two different approaches:
static void testApproaches(PairManager pman1, PairManager pman2) {
ExecutorService exec = Executors.newCachedThreadPool();
//pair manipulators - task-uri ce genereaza perechi pe baza obiectelor PairManager
PairManipulator pm1 = new PairManipulator(pman1);
PairManipulator pm2 = new PairManipulator(pman2);
//task-uri ce manipuleaza perechi utilizand obiectele pairManager
PairChecker pcheck1 = new PairChecker(pman1);
PairChecker pcheck2 = new PairChecker(pman2);
exec.execute(pm1);//task pentru pm1 - generare a perechilor prin obiectul pm1
exec.execute(pm2); //task pentru pm2 - generare a perechilor prin obiectul pm2
exec.execute(pcheck1); //task pentru verificarea perechilor - pt cele generate prin pm1
exec.execute(pcheck2);//task pentru verificarea perechilor - pt cele generate prin pm2
try {
TimeUnit.MILLISECONDS.sleep(500); //suspendarea thread-ului pentru 500 milisecunde
} catch (InterruptedException e) {
System.out.println("Sleep interrupted");
}
System.out.println("pm1: " + pm1 + "\npm2: " + pm2);
System.exit(0);
}
public static void main(String[] args) {
PairManager pman1 = new PairManager1();
PairManager pman2 = new PairManager2();
testApproaches(pman1, pman2);
}
}