記錄一次壓測中遇到的線程阻塞問題
java能夠使用反射來執行方法調用,反射根據一個類名獲得Class對象,再由對象名和給定的參數集拿到Method對象,就能夠經過Method.invoke來執行java
@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方法獲取到的jvm
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獲取的,代碼以下:ide
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.ui
調用次數沒有超過這個閾值的時候其實使用的仍是NativeMethodAccessor.invoke),即沒有if裏面那些處理。超出閾值後執行if中的邏輯,native的就被搞成了MethodAccessorImpl。同時setDelegatethis
這個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版code
sun.reflect.GeneratedMethodAccessor<N>是怎麼出現的呢?對象
默認這個優化是開啓的且閾值是15,在前面少數調用時,調用的實際上是native版的invoke0,超出閾值後,就開始使用MethodAccessorGenerator.generateMethod,這裏面最終會調到一個genarateName方法get
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; } }