2017-05-27 5 views
0

Ich baue eine Java-Anwendung und ich muss verfolgen, wie viele Sekunden seit dem Start des Programms vergangen sind. Ich versuche, dies mit einem Thread zu erreichen, so habe ich eine Hauptklasse, die den timeController Thread erstellt, wartet 5 Sekunden und stoppt dann, zu Testzwecken ist das einzige, was timeController jetzt tun soll, ist, die verstrichenen Sekunden zu drucken alle 0,5 Sekunden. Aber bedenken Sie, dass mein Endziel ist, mehrere Threads eines anderen Objekts zu haben, die die synchron verstrichenen Sekunden an timeController fragen. Für jetzt druckt es nur die erste Calendar.SECOND und aktualisiert diesen Wert nie, da es für 5 Sekunden vor der Unterbrechung läuft und jede halbe Sekunde aktualisiert, würde ich erwarten, etwas wie 44 44 45 45 46 46 47 47 48 48 zu sehen (vorausgesetzt, wenn es begann die Systeme Sekunden waren 44). Vielen Dank.Wie verfolgen Sie die Sekunden?

public class Main { 

    public static void main(String[] args) { 

     TimeController timeCon = TimeController.getInstance(); 

     timeCon.start(); 
     try { 
      Thread.sleep(5000); 
      timeCon.stop(); 
     } catch (Exception e){ 
      //ignore for now 
     } 
    } 
} 

public class TimeController implements Runnable{ 

    private static TimeController instance = null; 
    private volatile Thread timeCon; 

    private Calendar calendarInstance = Calendar.getInstance(); 
    private int secondsElapsed = 0; 
    private int incialSeconds = 0; 

    public int getElapsedSeconds(){ 
     return secondsElapsed; 
    } 

    public static TimeController getInstance(){ 
     if(instance == null){ 
      instance = new TimeController(); 
     } 
     return instance; 
    } 

    public void start(){ 
     timeCon = new Thread(this); 
     timeCon.start(); 
    } 

    public void stop(){ 
     timeCon = null; 
    } 

    @Override 
     public void run() { 
      Thread thisThread = Thread.currentThread(); 
      while (thisThread == timeCon) { 
       try { 
        Thread.sleep(500); 
        secondsElapsed = calendarInstance.get(Calendar.SECOND) - incialSeconds; 
        System.out.println(getElapsedSeconds()); 
       } catch (Exception e){ 
        //Ignore for now. 
       }    
      } 
     } 
} 
+1

Eines der wichtigsten Dinge ersetzen, um zu erfahren Multi-Threading ist; ** Verwenden Sie Multithreading nur, wenn dies sinnvoll ist **. wenn Sie es nicht mit einem Thread tun können. Ansonsten fügen Sie einfach Komplexität und Fehler hinzu. –

Antwort

2

Vorerst druckt nur die erste Calendar.SECOND und nie aktualisiert dieser Wert

Es scheint, dass Sie eine gleichzeitige Lösung für Ihr Timing-Problem zur Verfügung stellen möchten, aber keine der Code in Ihrem Timing-Thread ist synchronisiert. Dieser Block ist zumindest suspekt: ​​

private Calendar calendarInstance = Calendar.getInstance(); 
private int secondsElapsed = 0; 
private int incialSeconds = 0; 

public int getElapsedSeconds(){ 
    return secondsElapsed; 
} 

Hier läuft keine Synchronisation. Da Threads möglicherweise auf verschiedenen Kernen mit unterschiedlichem lokalen Cache-Speicher ausgeführt werden, gibt es keine Garantie dafür, dass Änderungen an einer Variablen in einem Thread jemals für einen anderen Thread sichtbar sind, der auf einem anderen Prozessorkern ausgeführt wird. Das passiert wahrscheinlich in deinem Code.

Sie sollten den Statusbereich Ihrer veränderbaren Objekte (hier TimerController) sorgfältig definieren und eine Thread-Sicherheitsrichtlinie implementieren, die für Ihren Anwendungsfall sinnvoll ist. Das Ziel Ihrer Richtlinie besteht darin, den veränderlichen Zustand Ihrer Objekte vor Wettbewerbsbedingungen zu schützen, die zu Ausfällen und Sicherheitsfehlern führen (d. H. Um ungültige Zustandsübergänge zu verhindern). Eine gängige Methode, dies zu beheben, besteht darin, das Monitormuster zu verwenden, um durch die Verwendung von Sperren gegenseitige Ausgrenzung und Sichtbarkeit zu erreichen.

+0

Vielen Dank für die Antwort, ich bin neu zu Multi-Threading immer noch versuchen zu verstehen, wie alles funktioniert. Was würdest du vorschlagen, um mein Problem zu lösen? Wie würde ich es synchronisieren? –

+0

Ich sehe Ihren Punkt, aber zu Testzwecken, auch wenn ich keine zusätzlichen Methoden überhaupt verwende und nur alles innerhalb des Laufs codiere, sind die Ergebnisse die gleichen. –

1

Sie sollten Zeit zu dem Zeitpunkt verstrichen compute Sie es brauchen, jedes Mal Sie brauchen, und nur, wenn Sie es brauchen, in dem selben Thread als Haupt-Code. Es besteht keine Notwendigkeit für einen separaten Thread, der ständig einen verstrichenen Zeitwert berechnet und speichert.

0

Vielen Dank für alle, die versucht haben zu helfen, während es in Zukunft ein Synchronisierungsproblem geben wird, wenn mehrere Threads versuchen, die Zeit vom TimeController zu bekommen, was für diese spezielle Instanz des Problems nicht der Fall ist. Ich stellte fest, dass das Problem darin bestand, dass ich einen statischen Verweis auf einen Kalender aufbewahrte, obwohl ich Calendar.getInstance() innerhalb der run-Methode verwenden sollte, um den Verweis bei jedem Lauf zu aktualisieren. Hier ist, wie es aussehen sollte:

@Override 
public void run() { 
    Thread thisThread = Thread.currentThread(); 
    while (thisThread == timeCon) { 
     try { 
      Thread.sleep(500); 
      secondsElapsed = Calendar.getInstance().get(Calendar.SECOND) - incialSeconds; 
     } catch (Exception e){ 
      //Ignore for now. 
     } 
    } 
} 
0

Sie können Ihre Klasse mit

public enum TimeController { 
    INSTANCE; 

    final long started = System.currentTimeMillis(); 

    public int getElapsedSeconds() { 
     return (System.currentTimeMillis() - started)/1000; 
    } 

    @Deprecated 
    public static TimeController getInstance() { 
     return INSTANCE; 
    } 
} 

oder sogar simplier

public enum TimeController { 
    ; 

    static final long started = System.currentTimeMillis(); 

    public static int getElapsedSeconds() { 
     return (System.currentTimeMillis() - started)/1000; 
    } 
} 
Verwandte Themen