Przetwarzanie współbieżne |
---|
Wojciech Kupczyk 94415 |
Cele laboratorium:
synchronizacja wątków w Javie
W Javie wątki są obiektami zdefiniowanymi za pomocą specjalnego rodzaju klas.
Program wielowątkowy definiujemy na dwa sposoby:
jako podklasę klasy Thread;
implementując interfejs Runnable.
W naszym programie wykorzystamy pierwszy sposób.
Ad. 1.
Zadanie polegało na zaimplementowaniu symulacji pubu w Javie. Projekt składa się z 3 klas: Klient, Pub, Main. Poniżej przedstawiam kody źródłowe zawarte w każdym z tych plików, oraz fragment przykładowego wydruku.
Pub.java:
6 public class Pub { 7 8 int ilKlientow, ilKufli; 9 int[] tabKufli; 10 11 //konstruktor Pubu 12 public Pub(int ilKlientow, int ilKufli) { 13 this.ilKufli = ilKufli; 14 this.ilKlientow = ilKlientow; 15 tabKufli = new int[this.ilKufli]; 16 for (int i = 0; i < this.ilKufli; i++) { 17 tabKufli[i] = 1; //puste kufle 18 } 19 } 20 21 // Zajecie wolnego kufla przez klienta, lub oczekiwanie na zwolnienie jednego z zajetych kufli. 22 public synchronized void zabierzKufel(Klient klient) { 23 System.out.println(klient.idKlienta + " klient oczekuje na wolny kufel."); 24 while (true) { 25 try { 26 for (int i = 0; i < ilKufli; i++) //petla po wszystkich kuflach 27 { 28 //jesli dany kufel jest wolny to zabieramy 29 if (tabKufli[i] == 1) { 30 tabKufli[i] = 0; 31 klient.idZajetegoKufla = i; 32 break; 33 } 34 } 35 if (klient.idZajetegoKufla == -1) { 36 wait(); // jesli nie znaleziono zadnego wolnego kufla to czekamy 37 } else { 38 break; 39 } 40 } catch (InterruptedException ex) { 41 Logger.getLogger(Pub.class.getName()).log(Level.SEVERE, null, ex); 42 System.out.println("Wyjatek w metodzie zabierzKufel !!! "); 43 } 44 } 45 System.out.println(klient.idKlienta + " klient dostal kufel " + (klient.idZajetegoKufla + 1)); 46 } 47 48 //nalewanie piwa, klient jako argument 49 public synchronized void nalewanie(Klient klient) { 50 try { 51 System.out.println(klient.idKlienta + " klient nalewa piwo do kufla " + (klient.idZajetegoKufla + 1)); 52 Thread.sleep(5000); 53 System.out.println(klient.idKlienta + " klient nalal piwo do kufla " + (klient.idZajetegoKufla + 1)); 54 } catch (InterruptedException ie) { 55 System.out.println("Wyjatek w metodzie nalewanie !!!"); 56 } 57 } 58 59 // oddawanie zajetego kufla 60 public synchronized void oddawanie(Klient klient) { 61 System.out.println(klient.idKlienta + " klient zwalnia kufel nr " + (klient.idZajetegoKufla + 1)); 62 tabKufli[klient.idZajetegoKufla] = 1; //oddanie kufla 63 klient.idZajetegoKufla = -1; 64 notifyAll(); //budzenie oczekujacych klientow 65 } 66 67 } |
---|
Klient.java:
2 // klasa Klient 3 class Klient extends Thread { 4 5 Pub pub; 6 int idKlienta; 7 int idZajetegoKufla; 8 9 // konstruktor klienta 10 public Klient(int nr, Pub pub) { 11 this.idKlienta = nr; 12 this.pub = pub; 13 idZajetegoKufla = -1; // domyslnie klient nie posiada kufla 14 } 15 16 public void run() { 17 //klient pije 2 piwa 18 for (int i = 1; i <= 2; i++) { 19 pub.zabierzKufel(this); 20 pub.nalewanie(this); 21 System.out.println(idKlienta + " klient pije piwo w kuflu " + (idZajetegoKufla + 1)); // picie piwa 22 pub.oddawanie(this); 23 } 24 } 25 } |
---|
Main.java:
1 package pub; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 int ilKufli = 3; 7 int ilKlientow = 5; 8 9 Pub pub = new Pub(ilKlientow, ilKufli); 10 Klient[] klienci = new Klient[ilKlientow]; 11 //utworzenie watkow 12 for (int k = 0; k < ilKlientow; k++) { 13 klienci[k] = new Klient(k + 1, pub); 14 } 15 //start watkow 16 for (int j = 0; j < ilKlientow; j++) { 17 klienci[j].start(); 18 } 19 } 20 } 21 |
---|
Ad. 2.
W zadaniu tym należało zastosować metodę trylock. Utworzyliśmy dwa rygle :
Lock kran = new ReentrantLock();
Lock bar = new ReentrantLock();
Modyfikacja kodu polegała na zmianie funkcji oczekiwania na kufel oraz nalewania piwa. Poniżej przedstawiam zmodyfikowane fragmenty metod zabierzKufel oraz nalewanie.
if (bar.tryLock()) // czy bar jest wolny? { try { for (int indeks = 0; indeks < ilKufli; indeks++) { if (tabKufli[indeks] == 1) { tabKufli[indeks] = 0; klient.idZajetegoKufla = indeks; break; } } if (klient.idZajetegoKufla != -1) { break; } } finally { bar.unlock(); //zwalniamy bar dla innych } } |
if(kran.tryLock()) //czy kran jest wolny? { try { System.out.println(klient.idKlienta + " klient nalewa piwo do kufla " + (klient.idZajetegoKufla + 1)); Thread.sleep(5000); System.out.println(klient.idKlienta + " klient nalal piwo do kufla " + (klient.idZajetegoKufla + 1)); break; } catch(InterruptedException ie) { System.out.println("Wyjatek: nalewanie sleep"); } finally { kran.unlock(); //zwalniamy kran dla innych } |
---|