Exercise index of this lecture   Alphabetic index   Course home   

Exercises and solutions
Samtidighed i Java


14.1   Opgave om logging af transaktioner i en bank med filialer  

I forlængelse af ovenstående eksempel, hvor to filialer i en bank opererer samtidigt på fælles konti, bedes I indføre en BankLogging klasse, som skal holde styr på følgende:
    Hvilke operationer der udføres på de forskellige konti i banken Klokkeslæt for gennemførelsen af en transaktion Rækkefølgen af transaktionerne
En instans af klassen BankLogging overføres til alle Konto objekter. Når der gennemføres en transaktion på en konto registreres forskellige data om transaktionen i loggen.

Vi kan bl.a. bruge denne log til at finde ud af i hvilken rækkefølge operationerne udføres fra de to samtidigt udførende filialer i eksemplet ovenfor.

Hvad angår tidsbehandling henvises til metoden getTime mv. i klassen java.util.Calendar.


14.2   Opgave om synkroniserede skjalde  

I forlængelse af ovenstående eksempel kan man observere, at hvis den ene sang synges (f.eks.) 2 gange, og den anden sang 4 gange kører det samlede Java program aldrig til ende.

    Studer programmet og overbevis dig selv om årsagen til dette problem
Indfør nu en forandring i programmet, således at 'rest vers' fra den lange sang bliver sunget efter at den korte sang er sunget til ende

Solution
Vi skal sikre os, at dirigenten ikke anviser en sanger, som allerede er færdig med at synge. Vi angriber problemet i metoden tagScenen i klassen Dirigent. Vi indfører et boolsk array, færdig, som holder rede på når en sanger er færdig med alle vers. Denne variabel manipuleres gennem metoden af samme navn. Som man nok husker, er udsagnet
  scenenLedig && hvemØnskerAtSynge == næsteSanger
centralt for synkroniseringen mellem sangerne. Udtrykket fortæller under hvilke omstændigheder en bestemt sanger kan få scenen. Vi ændrer nu udsaget til følgende:
  scenenLedig && (hvemØnskerAtSynge == næsteSanger || færdig[enAndenEnd(hvemØnskerAtSynge)])
Med jævne ord, kan en sanger X gå på scenen hvis scenen er ledig OG (hvis der X's tur ELLER hvis den anden sanger er færdig). Vi bekymrer os her kun med situationen, hvor der er to sangere. Her følger min løsning:

/* Synkroniseret koncert, hvor hver skjald synger på skift,
   men hvor den længste sang også synges færdig */

class Skjald extends Thread{
  
  private String[] strofer;
  int forsinkelse;      // pause efter et vers
  int gentagelser;      // hvor mange gange synger jeg verset
  int mig;              // mit nummer
  Dirigent coordinator; // reference til dirigenten

  public Skjald(int mig, Dirigent coordinator, String[] strofer, 
                int forsinkelse, int gentagelser){
    super();
    this.mig = mig;
    this.coordinator = coordinator;
    this.strofer = strofer;
    this.forsinkelse = forsinkelse;
    this.gentagelser = gentagelser;
  }

  // udskriver ét vers ad gangen:
  private void syngVers(){
    coordinator.tagScenen(mig);
    StringBuffer str = new StringBuffer(100);
    for(int i = 0; i < strofer.length; i++){
      str.append(strofer[i] + "\n");
    } 
    System.out.println(str.toString());
    try{
      if (forsinkelse > 0) Thread.sleep(forsinkelse);
    } 
    catch (InterruptedException e) 
      {};
    coordinator.frigivScenen();
  }

  public void run(){
    for(int g = 1; g <= gentagelser; g++){
        syngVers();
    }
    coordinator.færdig(mig);
  }
} // end class Skjald

class Dirigent{
  
  boolean scenenLedig;
  int næsteSanger;
  boolean[] færdig = new boolean[3];  // færdig(i) iff sanger i
                                      // er færdig med sangen

  public Dirigent(int hvemStarter){
    scenenLedig = true; 
    næsteSanger = hvemStarter;
    for(int i = 1; i <= 2; i++) færdig[i] = false;
  }

  private int enAndenEnd(int i){
    if (i == 1) return(2);
    else if (i == 2) return(1);
    else return(0);
  }

  public synchronized void tagScenen(int hvemØnskerAtSynge){
   while (!(scenenLedig && 
             (hvemØnskerAtSynge == næsteSanger ||
              færdig[enAndenEnd(hvemØnskerAtSynge)]))
         ){
    try {
      wait();
    } catch (InterruptedException e) { }
   } // end while
   // scenenLedig && 
   // (hvemØnskerAtSynge == næsteSanger || færdig[enAndenEnd(hvemØnskerAtSynge)])
   scenenLedig = false;
   næsteSanger = enAndenEnd(hvemØnskerAtSynge);
  }

  public synchronized void frigivScenen(){
   scenenLedig = true;
   notifyAll();
  }

  public synchronized void færdig(int hvemFærdig){
    færdig[hvemFærdig] = true;
    notifyAll();
  }

}    

class Sangkor4{

  static String[] mesterJakob = 
    {"MESTER JAKOB, MESTER JAKOB", "SOVER DU, SOVER DU", 
     "HØRER DU EJ KLOKKEN, HØRER DU EJ KLOKKEN", 
     "BIM BAM BUM, BIM BAM BUM"};

  static String[] gladeJul =
    {"Glade jul, dejlige jul", "Engle daler ned i skjul!",
      "Hid de flyver med paradisgrønt", "Hvor de ser, hvad for Gud er kønt", 
     "Lønligt iblandt os de går", "Lønligt iblandt os de går"};


  public static void main(String[] args){
    Dirigent brorKalle = new Dirigent(2); // skjald 1 starter
   
    // virker bedst når der er lige mange vers
    Skjald skjald1 = new Skjald(1, brorKalle, mesterJakob, 1000, 2);
    Skjald skjald2 = new Skjald(2, brorKalle, gladeJul, 200, 5);

    skjald2.start();
    skjald1.start();  
  }
} // end class Sangkor4

Her er endvidere et link til det rene Java program .


Generated: Monday March 31, 2008, 12:09:56
on the system cs-unix