Monitory i inne mechanizmy synchronizacji - JAVA

0

Hej, napisałem kod do pewnego problemu ale muszę go przerobić, bo nie spełnia wymagań. Nie za bardzo wiem jak to zrobić.
Muszę poprawić ten kod w taki sposób, aby zwiększyć liczbę czytelników korzystających jednocześnie z czytelni poprzez umożliwienie wejścia większej liczby oczekujących czytelników.

KOD:

//plik CzytPisM.java
import java.util.Random;

//klasa realizująca operacje dostępu/opuszczenia czytelni -> monitor
class Czytelnia {
//aktualna liczba czytelników
  private int czytelnicy;
//czy w czytelni jest pisarz
  private boolean jestPisarz;

  public Czytelnia()
  {
    czytelnicy = 0;
    jestPisarz = false;

    System.out.println("Utworzono czytelnię.");
  }

//wywoływane przed czytaniem
  public synchronized void wejscieCzytelnika() {
    while(jestPisarz) {
      try {
        wait();
      } catch(InterruptedException e) {}
    }
    czytelnicy++;
  }
//wywoływane po zakończeniu czytania
  public synchronized void wyjscieCzytelnika() {
    czytelnicy--;
    if(czytelnicy==0) //czy ten warunek jest potrzebny?
      notify();
  }

//wywoływane przed pisaniem
  public synchronized void wejsciePisarza() {
    while(jestPisarz || czytelnicy>0) {
      try {
        wait();
      } catch(InterruptedException e) {}
    }
    jestPisarz = true;
  }
//wywoływane po zakończeniu pisania
  public synchronized void wyjsciePisarza() {
    jestPisarz = false;
    notify();   //czy nie lepiej notifyAll()?
  }

}

//wątek czytelnika
class Czytelnik extends Thread {
  Czytelnia czyt;
  String id;

  public Czytelnik(Czytelnia c, String nazwa) {
    czyt=c;
    id=nazwa;
  }

  public void run() {
    Random r=new Random();

    while (true) {
      try {
        sleep(500+r.nextInt(500)); //losowe opóźnienie wejścia
      } catch (InterruptedException e) {}

      System.out.println("Czytelnik "+id+" probuje wejść...");
      czyt.wejscieCzytelnika();

      System.out.println("Czytelnik "+id+" czyta.");
      try {
        sleep(500+r.nextInt(500)); //losowe opóźnienie czytania
      } catch (InterruptedException e) {}

      czyt.wyjscieCzytelnika();
      System.out.println("Czytelnik "+id+" wychodzi.");
    }
  }
}

//wątek pisarza
class Pisarz extends Thread {
  Czytelnia czyt;
  String id;

  public Pisarz(Czytelnia c, String nazwa) {
    czyt=c;
    id=nazwa;
  }

  public void run() {
    Random r=new Random();

    while (true) {
      try {
        sleep(500+r.nextInt(500)); //losowe opóźnienie wejścia
      } catch (InterruptedException e) {}

      System.out.println("Pisarz "+id+" probuje wejść...");
      czyt.wejsciePisarza();

      System.out.println("Pisarz "+id+" pisze kolejne wiekopomne dzieło.");
      try {
        sleep(800+r.nextInt(1200)); //losowe opóźnienie pisania
      } catch (InterruptedException e) {}

      czyt.wyjsciePisarza();
      System.out.println("Pisarz "+id+" wychodzi.");
    }
  }
}

//klasa główna
public class CzytPisM {

  public static void main(String[] arg) {
    Czytelnia czyt=new Czytelnia();

    Czytelnik czytelnicy[] = new Czytelnik[] {
      new Czytelnik(czyt,"Franek"), new Czytelnik(czyt,"Kasia"),
      new Czytelnik(czyt,"Mietek"), new Czytelnik(czyt,"Zosia")
    };

    Pisarz p1=new Pisarz(czyt,"Adam Mickiewicz");
    Pisarz p2=new Pisarz(czyt,"Bolesław Prus");

    for(int i=0; i<czytelnicy.length; i++)
      czytelnicy[i].start();
    p1.start();
    p2.start();

//uwaga: w obecnym rozwiązaniu wątki nie kończą działania
    try {
        for(int i=0; i<czytelnicy.length; i++)
            czytelnicy[i].join();
        p1.join();
        p2.join();
    } catch (InterruptedException e) {}
  }
}
1

Klasyka. IMHO na synchronized się tego nie da zrobić, musisz mieć osoby mutex na czytelników i pisarzy - jakoś tak to szło. Co za tym idzie, ja bym to robił na ReentrantLockach, bardziej granularna obsługa synchronizacji. Nie było na wykładzie? :)

1
Charles_Ray napisał(a):

IMHO na synchronized się tego nie da zrobić, musisz mieć osoby mutex na czytelników i pisarzy - jakoś tak to szło. Co za tym idzie, ja bym to robił na ReentrantLockach, bardziej granularna obsługa synchronizacji.

E tam, da się. Nawet ReentrantReadWriteLock co do zasady nie robi żadnej magii, tylko używa CAS-a zamiast synchronized.

Jaś Skwarczek napisał(a):

Muszę poprawić ten kod w taki sposób, aby zwiększyć liczbę czytelników korzystających jednocześnie z czytelni poprzez umożliwienie wejścia większej liczby oczekujących czytelników.

Weź taką sytuację:

  1. Wchodzi pisarz
  2. Przychodzi n czytelników, wszyscy muszą czekać (bo pisarz pisze).
  3. Wychodzi pisarz. Kogo on obudzi? Ile osób wejdzie do czytelni, a ile mogłoby?

1 użytkowników online, w tym zalogowanych: 0, gości: 1