Java 静态类中的线程安全性和泛型

Java 静态类中的线程安全性和泛型,java,multithreading,generics,static,thread-safety,Java,Multithreading,Generics,Static,Thread Safety,我有一个用于统计计算的Util类。在多个线程之间计算指数移动平均值。此外,该线程还传递不同的值,有些是双倍的,有些是长的。我想创建泛型,并确保在对方法的签名应用synchronized时 public class StatUtils { public static class WMA { // MMA } public static class EMA { /** The alpha. */ private st

我有一个用于统计计算的Util类。在多个线程之间计算指数移动平均值。此外,该线程还传递不同的值,有些是双倍的,有些是长的。我想创建泛型,并确保在对方法的签名应用synchronized

    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;
        }
    }
}

计算方法是线程安全的吗?如果是,是否可以使此静态类成为泛型类?

只要同步,您的方法是线程安全的,但不能使泛型类成为静态类。泛型类型在实例化类时解析,但在静态类中永远不会发生这种情况

您可以定义一个通用方法,如:

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

但在您的情况下,您可以简单地使用double,因为长值可以毫无问题地转换为double。

只要同步,您的方法是线程安全的,但您不能将泛型设置为静态类。泛型类型在实例化类时解析,但在静态类中永远不会发生这种情况

您可以定义一个通用方法,如:

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

但是在您的情况下,您可以简单地使用double,因为长值可以毫无问题地转换为double。

是的,您当前的方法是线程安全的。但它可能没有整个
compute
方法被单个线程阻塞时那么有效

我不确定EMA算法,但如果您同意线程使用几乎最新的
staticOldValue
值,那么您可以对其进行如下改进:

  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;
    }
  }

是的,您当前的方法是线程安全的。但它可能没有整个
compute
方法被单个线程阻塞时那么有效

我不确定EMA算法,但如果您同意线程使用几乎最新的
staticOldValue
值,那么您可以对其进行如下改进:

  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;
    }
  }

问题似乎出在你们的课堂设计上。为什么要从构造函数实例化
static
类成员
staticAlpha
?我不确定确切的要求,但看看你的代码,我认为如果设计得当,你甚至不需要同步。请注意,这是一个错误,我没有实例化课程类。什么部分应该成为泛型?如果您想使用泛型类型而不是double,“compute”应该做什么?我用double计算价格。在另一个例子中,我用long计算时间段。这听起来仍然像是两种不同的方法,除非
double
中计算价格的代码与
long
中的计算时间段相同,问题似乎在于你的类设计。为什么要从构造函数实例化
static
类成员
staticAlpha
?我不确定确切的要求,但看看你的代码,我认为如果设计得当,你甚至不需要同步。请注意,这是一个错误,我没有实例化课程类。什么部分应该成为泛型?如果您想使用泛型类型而不是double,“compute”应该做什么?我用double计算价格。在其他方法中,我用long计算时间段。这听起来仍然像两种不同的方法,除非
double
中计算价格的代码与
long
中的计算时间段相同,但相反的方法会失去精度。如果时间有限,它是非常宝贵的。但是你不需要从双倍到长。只需使用double来存储结果。例如,(长)9223372036854775807的时间戳将存储为(双)9.223372036854776E18。如有必要,您可以不使用科学符号打印。当然,如果你使用19位长的数字,当从长转换为双精度时,你会丢失4个低有效数字。但是相反的,会丢失精度。如果时间有限,它是非常宝贵的。但是你不需要从双倍到长。只需使用double来存储结果。例如,(长)9223372036854775807的时间戳将存储为(双)9.223372036854776E18。如有必要,您可以不使用科学符号打印。当然,如果您使用19位长的数字,当从长到双精度转换时,您将丢失4位低有效数字。