package raceConditions; /** * Was passiert hier eigentlich? Zwei Threads arbeiten auf demselben Objekt, * weshalb dieses mittels synchronized kritische Bereiche absichert ( d. h. * read und write können nicht gleichzeitig ausgeführt werden). Das Problem ist, * dass es trotzdem zu unterschiedlichen Ergebnissen kommen kann, je nachdem * wie die Threads tatsächlich ausgeführt werden, da beide erst den aktuellen * Wert auslesen, diesen dann erhöhen und mittels write zurückschreiben. So kann * es vorkommen, dass beide den Anfangswert lesen (und entsprechend beide 2 * schreiben) oder dass einer read und write vollständig durchführt bevor der * andere liest, sodass der zweite den "neuen" Wert liest und entsprechend 4 * ausgibt. * * @author Stefan Berktold */ public class TimesTwo implements Runnable { private final SyncNumber n; private final String name; // zusätzlich - speichert den Namen (d1 oder d2) public TimesTwo(SyncNumber c, String tn) { // um Thread-Name erweitert n = c; name = tn; } @Override public void run() { print(this.name + ".run:Enter"); int i = n.read(); n.write(i * 2); //if (name.equals("d1")) try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("write " + i * 2); print("println(write " + i*2 + ")"); print(this.name + ".run:Return"); } /* * Hinweis: Ich habe die main-Methode teilweise erweitert, sodass die * Threads in toString deren Farbe zurückgeben. Wir können das dann für die * Konsolenausgabe verwenden, um das Geschehen besser zu visualisieren. * Ich habe hier nichts geändert außer toString() in Thread überschrieben * und in TimesTwo die Membervariable über den angepassten Konstruktor zu * setzen. */ public static void main(String[] args) { SyncNumber n = new SyncNumber(); TimesTwo d1 = new TimesTwo(n, "d1"); TimesTwo d2 = new TimesTwo(n, "d2"); new Thread(d1){ public String toString() { return "\u001B[34m"; } // blau }.start(); // Thread 1 new Thread(d2){ public String toString() { return "\u001B[31m"; } // rot }.start(); // Thread 1 } // zusätzlich für die Konsolenausgabe (um das Geschehen zu visualisieren); // setzt die Farbe für den aktuellen Thread und gibt die Nachricht aus. final static void print(String msg) { System.out.println(Thread.currentThread().toString() + msg); } }