如何使用 JDK 6 的方法句柄?
How can I use method handles with JDK 6?
这里的情况很奇怪。我需要多次调用相同的 class 实例方法(1000/秒范围),但无法导入或构建所需的库。我正在尝试在我的 JEE 项目中调用一个方法,该方法使用应用程序服务器提供的库中的 class。 JEE 项目仍然需要 运行 在其他应用程序服务器上,所以我不能简单地针对该库进行构建。反思是我认为唯一的解决办法。
执行速度如此之快时,使用反射的执行时间比直接调用慢几个数量级。
经过一些研究,我发现了 static final MethodHandles:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
public class Test {
static final MethodHandle sfmh;
static {
MethodHandle mh = null;
try {
final Class<?> clazz = Class.forName("com.me.lib");
Method m = clazz.getMethod("MyMethod");
mh = MethodHandles.lookup().unreflect(m);
} catch (Throwable e) {
mh = null;
}
sfmh = mh;
}
public static void main(String[] args) throws Throwable {
int i = 0;
System.out.println("starting");
long start = System.currentTimeMillis();
for(i = 0; i < 1000000000; i++) {
sfmh.invokeExact();
}
long total = System.currentTimeMillis() - start;
System.out.println("Time: " + total + " milliseconds");
}
}
效果很好,让我获得了可接受的速度结果(慢 2-4 倍,而不是慢 200 倍)。这个完美的解决方案似乎有一个问题——我需要在 Java 6 上 运行(嘘,嘶嘶声,这是一个要求)
针对 1.6 进行编译时,我得到:
Invocation of polymorphic methods not allowed for source level below
1.7
上线
sfmh.invokeExact();
是否有任何解决方案可以利用适用于 1.6 的 MethodHandle 概念?
不,方法句柄仅在 JDK 7 中添加,在此之前无法访问。您也不能针对方法句柄 API 编译 class,因为 JDK 6 不理解 @PolymorphicSignature
注释;方法句柄的编译方式与使用合成签名的其他方法略有不同。
除此之外,反射在现代 JVM 上并不慢,也许 运行 您的应用程序在最近的 JVM 上运行?在 JVM v8 上 运行 Java 6 代码完全没问题。最后,由于多种原因,您的基准测试存在缺陷。也许您的反射代码即使在今天也不慢? JVM 知道一个称为 inflation 的概念,它避免了 JNI 调用的性能开销。
以下是在 v8 JVM 上使用 harness 的一些结果,比较了反射、公共调用和方法句柄:https://gist.github.com/raphw/881e1745996f9d314ab0
这里的情况很奇怪。我需要多次调用相同的 class 实例方法(1000/秒范围),但无法导入或构建所需的库。我正在尝试在我的 JEE 项目中调用一个方法,该方法使用应用程序服务器提供的库中的 class。 JEE 项目仍然需要 运行 在其他应用程序服务器上,所以我不能简单地针对该库进行构建。反思是我认为唯一的解决办法。
执行速度如此之快时,使用反射的执行时间比直接调用慢几个数量级。
经过一些研究,我发现了 static final MethodHandles:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
public class Test {
static final MethodHandle sfmh;
static {
MethodHandle mh = null;
try {
final Class<?> clazz = Class.forName("com.me.lib");
Method m = clazz.getMethod("MyMethod");
mh = MethodHandles.lookup().unreflect(m);
} catch (Throwable e) {
mh = null;
}
sfmh = mh;
}
public static void main(String[] args) throws Throwable {
int i = 0;
System.out.println("starting");
long start = System.currentTimeMillis();
for(i = 0; i < 1000000000; i++) {
sfmh.invokeExact();
}
long total = System.currentTimeMillis() - start;
System.out.println("Time: " + total + " milliseconds");
}
}
效果很好,让我获得了可接受的速度结果(慢 2-4 倍,而不是慢 200 倍)。这个完美的解决方案似乎有一个问题——我需要在 Java 6 上 运行(嘘,嘶嘶声,这是一个要求)
针对 1.6 进行编译时,我得到:
Invocation of polymorphic methods not allowed for source level below 1.7
上线
sfmh.invokeExact();
是否有任何解决方案可以利用适用于 1.6 的 MethodHandle 概念?
不,方法句柄仅在 JDK 7 中添加,在此之前无法访问。您也不能针对方法句柄 API 编译 class,因为 JDK 6 不理解 @PolymorphicSignature
注释;方法句柄的编译方式与使用合成签名的其他方法略有不同。
除此之外,反射在现代 JVM 上并不慢,也许 运行 您的应用程序在最近的 JVM 上运行?在 JVM v8 上 运行 Java 6 代码完全没问题。最后,由于多种原因,您的基准测试存在缺陷。也许您的反射代码即使在今天也不慢? JVM 知道一个称为 inflation 的概念,它避免了 JNI 调用的性能开销。
以下是在 v8 JVM 上使用 harness 的一些结果,比较了反射、公共调用和方法句柄:https://gist.github.com/raphw/881e1745996f9d314ab0