/****************************************************************/
/* Prof. Dr. Carsten Vogt                                       */
/* FH Koeln, Fak. 07 / Nachrichtentechnik                       */
/* http://www.nt.fh-koeln.de/vogt                               */
/*                                                              */
/* synchronized:                                                */
/* Ein Objekt bietet eine Methode an, von der ein Teil wechsel- */
/* seitig ausgeschlossen auszufuehren ist, der Rest aber un-    */
/* eingeschraenkt nebenlaeufig ausgefuehrt werden kann. Diese   */
/* Bedingung wird mit Hilfe eines "Synchronisationsobjekts"     */
/* durchgesetzt.                                                */
/****************************************************************/

class SynchronObjekt {
 /* Synchronisationsobjekt: hat weder Attribute noch Methoden,
    sondern wird nur als Parameter von synchronized() in einem
    anderen Objekt (s.u.: Zugriffsobjekt) verwendet. */
}

class ZugriffsObjekt {

 /* Objekt mit der Methode "zugriff()", die teilweise wechsel-
    seitig ausgeschlossen ausgefuehrt werden soll */

 private SynchronObjekt sobj;
  /* Synchronisationsobjekt, ueber das der Zugriff auf das
     Zugriffsobjekt synchronisiert wird */

 /* Konstruktor: Setzen des Synchronisationsobjekts */

 ZugriffsObjekt(SynchronObjekt so) {
  sobj = so;
 }
 
 /* Methode, die teilweise wechselseitig ausgeschlossen ist */

 void zugriff(EinThread t) { 

  /* Erster Teil kann noch nebenlaeufig ausgefuehrt werden */
  System.out.println("Stufe 1 "+t.getName()+" beginnt.");
  try {
   /* Ausfuehrungsdauer erster Teil: 2 s */
   t.sleep(2000);
  } catch (java.lang.InterruptedException E) {}
  System.out.println("Stufe 1 "+t.getName()+" endet.");

  /* Zweiter Teil soll wechselseitig ausgeschlossen ausgefuehrt
     werden: Sicherstellung durch Aufruf von synchronized mit
     einem Synchronisationsobjekt (hier sobj) */
  synchronized (sobj) {
   System.out.println("######## STUFE 2 "+t.getName()+" BEGINNT.");
   try {
   /* Ausfuehrungsdauer zweiter Teil: 2 s */
    t.sleep(2000);
   } catch (java.lang.InterruptedException E) {}
   System.out.println("######## STUFE 2 "+t.getName()+" ENDET.");
  }

 }

}

class EinThread extends Thread {

 /* Thread zum Zugriff auf das Zugriffsobjekt */

 private ZugriffsObjekt zobj;
   /* Zugriffsobjekt */

 /* Konstruktor: Setzen der Attribute */

 EinThread(String s, ZugriffsObjekt zo) {
  this.setName(s);
  zobj = zo;
 }

 /* Aktionen des Thread: Aufruf der Zugriffsmethode des Objekts
    in Abstaenden von 2 Sekunden */

 public void run() {
  try {
   for (;;)
    { zobj.zugriff(this);;
      sleep(2000);
    }
   } catch (InterruptedException E)
     { System.out.println("Thread "+this.getName()+" terminiert"); }
 }

}

public class Synchron2 {

 /* Hauptprogramm */

 public static void main(String[] args) {

  System.out.println();
  /* Erzeugung der Objekte und zweier Threads */
  SynchronObjekt sobj = new SynchronObjekt();
  ZugriffsObjekt zobj = new ZugriffsObjekt(sobj);
  EinThread T1 = new EinThread("--T1--",zobj);
  EinThread T2 = new EinThread("**T2**",zobj);

  /* Starten der Threads */
  T1.start();
  T2.start();
  
 }

}

