记录一次压测中遇到的线程阻塞问题
java 能够应用反射来执行办法调用,反射依据一个类名失去 Class 对象,再由对象名和给定的参数集拿到 Method 对象,就能够通过 Method.invoke 来执行
@CallerSensitive
public Object invoke(Object var1, Object... var2) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {if(!this.override && !Reflection.quickCheckMemberAccess(this.clazz, this.modifiers)) {Class var3 = Reflection.getCallerClass();
this.checkAccess(var3, this.clazz, var1, this.modifiers);
}
MethodAccessor var4 = this.methodAccessor;
if(var4 == null) {var4 = this.acquireMethodAccessor();
}
return var4.invoke(var1, var2);
}
由下面的代码能够看进去 invoke 是由 MethodAccessor 来执行的,MethodAccessor 又是 acquireMethodAccessor 办法获取到的
private MethodAccessor acquireMethodAccessor() {
MethodAccessor var1 = null;
if(this.root != null) {var1 = this.root.getMethodAccessor();
}
if(var1 != null) {this.methodAccessor = var1;} else {var1 = reflectionFactory.newMethodAccessor(this);
this.setMethodAccessor(var1);
}
return var1;
}
MethodAccessor 是通过 ReflectionFactory 的 newMethodAccessor 获取的,代码如下:
public MethodAccessor newMethodAccessor(Method var1) {checkInitted();
if(noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
} else {NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
var2.setParent(var3);
return var3;
}
}
如果 noInflation 为 true(不收缩,当 Java 虚拟机从 JNI 存取器改为字节码存取器的行为被称为 收缩(Inflation)),创立 MethodAccessorGenerator,否则 NativeMethodAccessor。NativeMethodAccessorImpl 中的 invoke 代码如下
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {if(++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
this.parent.setDelegate(var3);// 当这一步执行完之后,DelegatingMethodAccessorImpl 中的 delegate 就是 MethodAccessorImpl 而不是 NativeMethodAccessorImpl 了
}
return invoke0(this.method, var1, var2);
}
ReflectionFactory.inflationThreshold() 就是 jvm 的启动参数的 -Dsun.reflect.inflationThreshold,默认值是 15.
调用次数没有超过这个阈值的时候其实应用的还是 NativeMethodAccessor.invoke),即没有 if 外面那些解决。超出阈值后执行 if 中的逻辑,native 的就被搞成了 MethodAccessorImpl。同时 setDelegate
这个 setDelegate 要回看下面 DelegatingMethodAccessorImpl,有点像一个中间层,在 native 和 java 版之间转换
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;
DelegatingMethodAccessorImpl(MethodAccessorImpl var1) {this.setDelegate(var1);
}
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {return this.delegate.invoke(var1, var2);
}
void setDelegate(MethodAccessorImpl var1) {this.delegate = var1;}
}
据说 java 版的启动慢,然而执行快 (编译器能够优化);native 版的启动快,然而执行慢。所以 hotspot 的 jdk 做了个优化,调用次数少时用 native 版的,当发现调用次数多时,则调用 MethodAccessorGenerator.generateMethod() 来生成 Java 版的 MethodAccessor 的实现类,并且扭转 DelegatingMethodAccessorImpl 所援用的 MethodAccessor 为 Java 版
sun.reflect.GeneratedMethodAccessor<N> 是怎么呈现的呢?
默认这个优化是开启的且阈值是 15,在后面多数调用时,调用的其实是 native 版的 invoke0,超出阈值后,就开始应用 MethodAccessorGenerator.generateMethod,这外面最终会调到一个 genarateName 办法
private static synchronized String generateName(boolean var0, boolean var1) {
int var2;
if(var0) {if(var1) {
var2 = ++serializationConstructorSymnum;
return "sun/reflect/GeneratedSerializationConstructorAccessor" + var2;
} else {
var2 = ++constructorSymnum;
return "sun/reflect/GeneratedConstructorAccessor" + var2;
}
} else {
var2 = ++methodSymnum;
return "sun/reflect/GeneratedMethodAccessor" + var2;
}
}