2016-07-05 4 views
0

Ich habe eine Util-Klasse, die ich für die Berechnung der Statistik verwende. Ein exponentieller gleitender Durchschnitt wird unter mehreren Threads berechnet. Auch diese Threads passieren unterschiedliche Werte, manche mal doppelt und andere lang. Ich möchte Generika machen und auch sicher sein, dass bei der Anwendung synchronisiert auf die Signatur der Methode.Gewindesicherheit und Generika in einer statischen Klasse

public class StatUtils { 

    public static class WMA { 
     // MMA 
    } 
    public static class EMA { 

     /** The alpha. */ 
     private static double staticAlpha = 0.9; 

     /** The old value. */ 
     private static double staticOldValue = 1.0; 

     /** 
     * Compute. 
     * 
     * @param pValue the value 
     * @return the double 
     */ 
     public static synchronized double compute(double pValue) { 
      if (staticOldValue == 0.0) { 
       staticOldValue = pValue; 
       return pValue; 
      } 
      double lValue = staticOldValue + staticAlpha * (pValue - staticOldValue); 
      staticOldValue = lValue; 
      return lValue; 
     } 
    } 
} 

Ist das Rechenverfahren Thread-sicher? Wenn ja, ist es möglich, diese statische Klasse generisch zu machen?

+0

Problem mit Ihrer Klasse Design zu sein scheint . Warum willst du 'static' class member' staticAlpha' vom Konstruktor instanziieren? Ich bin mir nicht sicher über die genaue Anforderung, aber wenn ich auf deinen Code schaue, denke ich, dass du nicht einmal Synchronisation benötigst, wenn er richtig entworfen ist. –

+0

Beachten Sie, dass das ein Fehler war, dass ich Klasse natürlich nicht instanziieren –

+0

Welcher Teil sollte generisch werden? Wenn Sie einen generischen Typ anstelle von Doubles verwenden möchten, was sollte "compute" tun? –

Antwort

1

Solange synchronisiert, ist Ihre Methode threadsicher, aber Sie können keine generische statische Klasse erstellen. Der generische Typ wird aufgelöst, wenn die Klasse instanziiert wird, aber dies wird bei einer statischen Klasse niemals vorkommen.

public static synchronized <T extends Number> compute(T pValue) 

aber in Ihrem Fall können Sie einfach doppelt verwenden, da ein langer Wert problemlos verdoppeln gegossen werden kann:

Sie könnten eine generische Methode, wie definieren.

+0

Aber das Gegenteil hat einen Verlust an Genauigkeit. Und im Falle der Zeit ist es sehr wertvoll. –

+1

Aber Sie müssen nicht von Doppel zu lange werfen. Verwende einfach double, um das Ergebnis zu speichern. Zum Beispiel wird ein Zeitstempel von (lang) 9223372036854775807 als (doppelt) 9.223372036854776E18 gespeichert. Bei Bedarf können Sie ohne wissenschaftliche Notation drucken http://stackoverflow.com/questions/16098046/how-to-print-double-value-without-scientific-notation-using-java. Natürlich, wenn Sie mit 19 Ziffern langen Zahlen arbeiten, werden Sie die 4 weniger signifikanten Ziffern verlieren, wenn Sie von Lang zu Doppeltem handeln. –

1

Ja, Ihr aktueller Ansatz ist Thread-sicher. Aber es ist möglicherweise nicht so effizient, wie ganze compute Methode von einem einzigen Thread blockiert wird.

Ich bin über EMA-Algorithmus nicht sicher, aber wenn Sie sind in Ordnung, dass die Fäden verwenden fast up-to-date-Wert von staticOldValue dann können Sie verbessern es mögen:

public static class EMA { 

    /** The alpha. */ 
    private static double staticAlpha = 0.9; 

    /** The old value. */ 
    private static double staticOldValue = 1.0; 

    private static Object monitor = new Object(); 

    /** 
    * Compute. 
    * 
    * @param pValue the value 
    * @return the double 
    */ 
    public static double compute(double pValue) { 
     synchronized (monitor) { 
     if (staticOldValue == 0.0) { 
      staticOldValue = pValue; 
      return pValue; 
     } 
     } 

     double lValue = staticOldValue + staticAlpha * (pValue - staticOldValue); 
     synchronized (monitor) { 
     staticOldValue = lValue; 
     } 

     return lValue; 
    } 
    }