2016-04-08 13 views
1

Ich habe ein TimeBomb-Objekt. Ich muss die Bombe basierend auf einer Timing-Logik explodieren lassen. Die Bombe wartet maximal 10 Sekunden und in diesem Zeitintervall, wenn niemand in diesem Intervall die Bombe auf die letzte Zeit zurücksetzt, wird sie explodieren. Ich habe eine Implementierung gefunden. Ich beginne die Wartelogik, indem ich den Timer auf die aktuelle Uhrzeit um 16:24:40 Uhr setze. Jetzt soll die Bombe um 16:24:50 explodieren. Nach dem Schlafen für 2 Sekunden setze ich die Bombe auf die aktuelle Zeit um 16.24.42 Uhr zurück. Jetzt sollte die Bombe erst um 16:24:52 explodieren, da die maximale Wartezeit 10 Sekunden beträgt. Aber die Logik, die ich implementiert habe, explodiert immer um 16:24:50. Wo mache ich mich falsch?Warte-Logik für Inaktivität

public class TestTimeBomb { 

    public static void main(String[] args) throws InterruptedException { 
     TimeBomb bomb = new TimeBomb(); 
     long time1 = System.currentTimeMillis(); 
     System.out.println("First setting event at time " + getHumanReadableTime(time1)); 
     bomb.resetBomb(time1); 
     Job job = new Job(bomb); 
     new Thread(job).start(); 

     Thread.sleep(2000); 

     long time2 = System.currentTimeMillis(); 
     System.out.println("Second setting event at time " + getHumanReadableTime(time2)); 
     bomb.resetBomb(time2); 
    } 

    public static Date getHumanReadableTime(long time) { 
     Timestamp stamp = new Timestamp(time); 
     Date date = new Date(stamp.getTime()); 
     return date; 
    } 
} 

class Job implements Runnable { 

    TimeBomb bomb; 

    Job(TimeBomb bomb) { 
     this.bomb = bomb; 
    } 

    @Override 
    public void run() { 
     WaiterLogic waiterLogic = new WaiterLogic(bomb); 
     new Thread(waiterLogic).start(); 
    } 
} 

class WaiterLogic implements Runnable { 
    private TimeBomb test; 

    WaiterLogic(TimeBomb test) { 
     this.test = test; 
    } 

    @Override 
    public void run() { 

     long currentTimeMillis = System.currentTimeMillis(); 
     System.out.println("Entering while loop this job should end at " + TestTimeBomb.getHumanReadableTime(currentTimeMillis + 10000)); 
     while (true) { 
      long bombTime = test.getBombTime(); 
      long curentTime = System.currentTimeMillis(); 
      long diffTIme = curentTime - bombTime; 
      if (diffTIme > 10000) 
       break; 

     } 
     long end = System.currentTimeMillis(); 
     System.out.println("This job should have ended at" + TestTimeBomb.getHumanReadableTime(test.getBombTime() + 10000)); 
     System.out.println("But ended at time " + TestTimeBomb.getHumanReadableTime(end)); 
     System.out.println("Diff is " + (end - (test.getBombTime() + 10000))); 
    } 

} 

class TimeBomb { 

    private long bombTime; 

    public long getBombTime() { 
     return bombTime; 
    } 

    public void resetBomb(long bombTime) { 
     this.bombTime = bombTime; 
    } 
} 
+0

Ich denke, es ist wie erwartet – Sanjeev

+0

Beispielausgabe arbeiten: –

+0

Erste Einstellung Ereignis zum Zeitpunkt Fr 8. April 17.29.11 IST 2016 while-Schleife Anfang dieser Job bei Fr 8. April 17.29.21 IST 2016 enden soll Zweite Einstellung Veranstaltung um Zeit Fr Apr 08 17:29:13 IST 2016 Dieser Job sollte beendet seinFri Apr 08 17:29:23 IST 2016 Aber endete um Zeit Fr Apr 08 17:29:21 IST 2016 Diff ist - 2028 –

Antwort

2

Ich nehme an, das eine Gleichzeitigkeit Problem ist, wo die bombTime Variable nicht Thread-sicher ist.

Auf der einen Faden (main) Sie den Wert in bombTime und in einem anderen Thread Einstellung (WaiterLogic) Sie den Wert gerade lesen. Es gibt eine Race-Bedingung, bei der, wenn diese beiden Threads versuchen, diese Daten zur gleichen Zeit zu bekommen, die in jedem Thread zwischengespeicherten Daten inkonsistent werden können.

Es gibt ein paar Optionen diesen Vorgang Thread-sicher machen


Verwenden Synchronisation

Das synchronized Schlüsselwort einen Thread sperren, ein Objekt zu lassen verwendet wird, während es eine Aufgabe ausführt. synchronized so kann wie an den TimeBomb Klassenmethoden verwendet werden, verwendet werden:

class TimeBomb { 

    private long bombTime; 

    public synchronized long getBombTime() { 
     return bombTime; 
    } 

    public synchronized void resetBomb(long bombTime) { 
     this.bombTime = bombTime; 
    } 
} 

durch Zugabe von synchronized zu jeder Methode wird der Haupt-Thread die Zeitbombe Objekt zuzugreifen, wenn der WaiterLogic Thread ruft getBombTime warten. Der Thread wartet ebenfalls auf den Zugriff auf das timebomb-Objekt, wenn der Hauptthread resetBomb aufruft. Dies stellt sicher, dass jeder Thread die korrekte Kopie der bombTime Daten zwischenspeichert.


Verwenden flüchtigen Stichwort

Das Schlüsselwort volatile es solchen macht, dass ein Thread nie einen Wert zwischenspeichert. es wird immer direkt in die Erinnerung gehen und im Wesentlichen so tun, als wäre es in einem synchronisierten Block.

private volatile long bombTime; 

Verwenden einer Atom Objekt

Wikipedia beschreibt ein atomares Objekt:

In concurrent programming, eine Operation (oder eine Reihe von Operationen) ist atomar, linearisierbar, unteilbar oder unterbrechungsfrei, wenn es für den Rest des Systems augenblicklich erscheint.

In Java können Sie java.util.concurrent.atomic.AtomicLong für diesen Zweck verwenden. Dieses Objekt benötigt keine Schlüsselwörter volatile oder synchronized. Es wird alles von der Klasse selbst behandelt.

0

Verwenden Sie warten (10000) und benachrichtigen Sie (in resetBomb-Methode) statt Schleifen, es ist weniger zeitaufwendig.