Java 静态类中的线程安全性和泛型
我有一个用于统计计算的Util类。在多个线程之间计算指数移动平均值。此外,该线程还传递不同的值,有些是双倍的,有些是长的。我想创建泛型,并确保在对方法的签名应用synchronized时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
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位低有效数字。