
import java.io.*;

// Dieses Beispiel summiert mit Threads,  jeweils  1000 Zahlen
// Ergebnis sollte 10000 sein
// Problem:  Gemeinsamer Zugriff auf die Variable summe
// Abhilfe: zusaetzliche add-Methode

// Test1:  die Methode aus Thread05, fehlerhafte Summation
// Test2:  die Methode addSumme wird jedesmal in der Schleife aufgerufen
// Test3:  die Methode addSumme wird nach der Summation aufgerufen

// vier Threads, diesmal mit Aufruf start
// 10 * 1,2,3,4  addieren= Summe 100
public class Thread06  {

   private static void pause() {
    try {
      System.in.read();
    }
    catch (IOException e) {
    }
  }  // pause

    final int MAX=100000;


  private void test1() {
    MyThread1 t1,t2,t3,t4;
    t1 = new MyThread1(1,MAX);
    t2 = new MyThread1(2,MAX);
    t3 = new MyThread1(3,MAX);
    t4 = new MyThread1(4,MAX);
    summe = 0;
    long zeit1 =  System.nanoTime();
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    try {
      t2.join();
      t3.join();
      t1.join();
      t4.join();
    }
    catch (InterruptedException e) {
    }    
    long zeit2 =  System.nanoTime();
    System.out.println("Test1: Das Ergebnis sollte "+(MAX*10)+" sein");
    System.out.println("***************  Summe: "+Long.toString(summe) );  
    System.out.println("Zeit: "+(zeit2-zeit1) +" ns");
  } // test1


  private void test2() {
    MyThread2 t1,t2,t3,t4;
    t1 = new MyThread2(1,MAX);
    t2 = new MyThread2(2,MAX);
    t3 = new MyThread2(3,MAX);
    t4 = new MyThread2(4,MAX);
    summe = 0;
    long zeit1 =  System.nanoTime();
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    try {
      t2.join();
      t3.join();
      t1.join();
      t4.join();
    }
    catch (InterruptedException e) {
    }    
    long zeit2 =  System.nanoTime();
    System.out.println("\n\n\nTest2: Das Ergebnis sollte "+(MAX*10)+" sein");
    System.out.println("***************  Summe: "+Long.toString(summe) );  
    System.out.println("Zeit: "+(zeit2-zeit1) +" ns");
  } // test2


  private void test3() {
    MyThread3 t1,t2,t3,t4;
    t1 = new MyThread3(1,MAX);
    t2 = new MyThread3(2,MAX);
    t3 = new MyThread3(3,MAX);
    t4 = new MyThread3(4,MAX);
    summe = 0;
    long zeit1 =  System.nanoTime();
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    try {
      t2.join();
      t3.join();
      t1.join();
      t4.join();
    }
    catch (InterruptedException e) {
    }    
    long zeit2 =  System.nanoTime();
    System.out.println("\n\n\nTest3: Das Ergebnis sollte "+(MAX*10)+" sein");
    System.out.println("***************  Summe: "+Long.toString(summe) );  
    System.out.println("Zeit: "+(zeit2-zeit1) +" ns");
  } // test2


  public static void main(String[] args) {
    Thread06 frame = new Thread06();
    frame.test1();
    frame.test2();
    frame.test3();
    pause();
  }



  private long summe=0;

  private synchronized void addSumme(long i) {
    summe+=i;
  }

// innere Klasse
class MyThread1 extends Thread {
  private long nummer=0;
  private int n;

  public void run() {
    for (int i=0; i<n; i++) {
      summe+=nummer;  // unsichere Summation
    }
  }  // run


  public MyThread1 (long nr, int n) {
     nummer = nr;
     this.n=n;
  }

}  // myThread1


class MyThread2 extends Thread {
  private long nummer=0;
  private int n;

  public void run() {
    for (int i=0; i<n; i++) {
      addSumme(nummer);  // jetzt ist die Summe sicher, aber langsam
    }
  }  // run


  public MyThread2 (long nr, int n) {
     nummer = nr;
     this.n=n;
  }

}  // myThread2



// innere Klasse, aber hier  wird nur EINMAL addSumme aufgerufen
class MyThread3 extends Thread {
  private long nummer=0;
  private int n;

  public void run() {
    long summe=0;
    for (int i=0; i<n; i++) {
      summe+=nummer;
    }
    addSumme(summe);
  }  // run


  public MyThread3 (long nr, int n) {
     nummer = nr;
     this.n=n;
  }

}  // MyThread3





}


