난 그냥 지금 구글 크롬에서 애플릿을 사용하여 비슷한 문제가 있었다. 한마디로
:
- 차단 된 스레드가 VM가 클래스를로드 할 필요가있을 때 차단 될 수 있습니다.
- 클래스 자체를로드하는 프로세스가 무언가에 의해 차단되면 전체 앱에 대해 고정이 발생할 수 있습니다. 세부 사항에
는 :
- 내가 코드베이스와 크롬 = 하나의 클래스 파일 폴더 (어떤 병)
- 를 애플릿을 사용하지 오전 :
나는 다음과 같은 시나리오를했다 웹 사이트는 LiveConnect를 사용하여 애플릿에 포커스 이벤트를 전달합니다.
- 들어오는 JS 호출은
Executor
과 new Runnable() ...
을 사용하여 de- 대기 시간을 줄이기 위해 호출을 처리하므로 JS에 걸립니다. - 문제가 발생한 곳입니다.
설명 :
new Runnable()
는 JS 호출이 발생하기 전에로드되지 않은 annonymous 내부 클래스입니다.
- 따라서 JS 호출은 클래스로드를 트리거합니다.
- 하지만 클래스 로더는 들어오는 JS 호출을 처리하는 동일한 큐 또는 메커니즘을 통해 브라우저와 대화해야하기 때문에 차단됩니다 (추측). ->
waitForMessage()
"Thread-20" daemon prio=4 tid=0x052e8400 nid=0x4608 in Object.wait() [0x0975d000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at sun.plugin2.message.Queue.waitForMessage(Unknown Source)
- locked <0x29fbc5d8> (a sun.plugin2.message.Queue)
at sun.plugin2.message.Pipe$2.run(Unknown Source)
at com.sun.deploy.util.Waiter$1.wait(Unknown Source)
at com.sun.deploy.util.Waiter.runAndWait(Unknown Source)
at sun.plugin2.message.Pipe.receive(Unknown Source)
at sun.plugin2.main.client.MessagePassingExecutionContext.doCookieOp(Unknown Source)
at sun.plugin2.main.client.MessagePassingExecutionContext.getCookie(Unknown Source)
at sun.plugin2.main.client.PluginCookieSelector.getCookieFromBrowser(Unknown Source)
at com.sun.deploy.net.cookie.DeployCookieSelector.getCookieInfo(Unknown Source)
at com.sun.deploy.net.cookie.DeployCookieSelector.get(Unknown Source)
- locked <0x298da868> (a sun.plugin2.main.client.PluginCookieSelector)
at sun.net.www.protocol.http.HttpURLConnection.setCookieHeader(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.writeRequests(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
- locked <0x2457cdc0> (a sun.net.www.protocol.http.HttpURLConnection)
at com.sun.deploy.net.HttpUtils.followRedirects(Unknown Source)
at com.sun.deploy.net.BasicHttpRequest.doRequest(Unknown Source)
at com.sun.deploy.net.BasicHttpRequest.doGetRequestEX(Unknown Source)
at com.sun.deploy.cache.ResourceProviderImpl.checkUpdateAvailable(Unknown Source)
at com.sun.deploy.cache.ResourceProviderImpl.isUpdateAvailable(Unknown Source)
at com.sun.deploy.cache.DeployCacheHandler.get(Unknown Source)
- locked <0x245727a0> (a java.lang.Object)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
- locked <0x24572020> (a sun.net.www.protocol.http.HttpURLConnection)
at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at sun.plugin2.applet.Applet2ClassLoader.getBytes(Unknown Source)
at sun.plugin2.applet.Applet2ClassLoader.access$000(Unknown Source)
at sun.plugin2.applet.Applet2ClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.plugin2.applet.Applet2ClassLoader.findClass(Unknown Source)
at sun.plugin2.applet.Plugin2ClassLoader.loadClass0(Unknown Source)
at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
- locked <0x299726b8> (a sun.plugin2.applet.Applet2ClassLoader)
at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
- locked <0x299726b8> (a sun.plugin2.applet.Applet2ClassLoader)
at java.lang.ClassLoader.loadClass(Unknown Source)
당신이 메시지를 기다리는 볼 수 있듯이 : 여기
는 클래스의로드를 시도 차단 된 스레드입니다.
"Applet 1 LiveConnect Worker Thread" prio=4 tid=0x05231800 nid=0x1278 waiting for monitor entry [0x0770e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at MyClass.myMethod(MyClass.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.plugin.javascript.Trampoline.invoke(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.plugin.javascript.JSClassLoader.invoke(Unknown Source)
at sun.plugin2.liveconnect.JavaClass$MethodInfo.invoke(Unknown Source)
at sun.plugin2.liveconnect.JavaClass$MemberBundle.invoke(Unknown Source)
at sun.plugin2.liveconnect.JavaClass.invoke0(Unknown Source)
at sun.plugin2.liveconnect.JavaClass.invoke(Unknown Source)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$DefaultInvocationDelegate.invoke(Unknown Source)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo.doObjectOp(Unknown Source)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$LiveConnectWorker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
추가적인 다른 스레드가 동일한 방식으로 차단 된 여기 차단 우리 JS 수신 통화가 동시에
. 모든 후속 클래스로드 요청은 첫 번째 차단 된 클래스로드 스레드에 의해 차단 된 것으로 가정합니다.
앞서 언급했듯이 클래스 로딩 프로세스는 보류중인 JS 호출에 의해 차단되며로드되지 않은 클래스에 의해 차단됩니다.
솔루션 : 호출하기 전에 애플릿의 생성자에서 모든 관련 클래스를로드
- 트리거는 JS에서 할 수있다.
- 클래스 파일을 개별적으로로드하지 않고 jar 파일에서로드하는 것이 도움이 될 수 있습니다. 그 뒤에있는 이론은 다음과 같습니다. 클래스 로더는 jar 파일에서 클래스를로드하기 위해 브라우저와 통신 할 필요가 없습니다 (
- 1과 조합시 : 동적 인 Proxy 클래스를 사용하여 들어오는 JS 호출을 모두 랩핑합니다. 그리고 Executor에서 독립적으로 실행
내 구현을 # 3 :
public class MyClass implements JsCallInterface
{
private final JsCallInterface jsProxy;
private final static interface JsCallInterface
{
public void myMethod1Intern(String param1, String param2);
}
private final class JsCallRunnable implements Runnable
{
private final Method method;
private final Object[] args;
private JsCallRunnable(Method method, Object[] args)
{
this.method = method;
this.args = args;
}
public void run()
{
try
{
method.invoke(MyClass.this, args);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
public MyClass()
{
MyUtilsClass.class.getName(); // load class
JsCallRunnable.class.getName(); // load class
InvocationHandler jsCallHandler = new InvocationHandler()
{
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable
{
MyUtilsClass.executeInExecutor(new JsCallRunnable(method, args));
return null;
}
};
jsProxy = (JsCallInterface) Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class<?>[] { JsCallInterface.class }, jsCallHandler);
}
public void myMethod1(String param1, String param2)
{
jsProxy.myMethod1Intern(param1, param2);
// needs to be named differently than the external method or else the proxy will call this method recursively
// alternatively the target-class in "method.invoke(MyClass.this, args);" could be a different instance of JsCallInterface
}
public void myMethod1Intern(String param1, String param2)
{
// do actual work here
}
}
참조 용 0x00000000472bc000에 대한 다른 항목이 있습니까? –
아니요, 같은 덤프에 없습니다. 0x00000000472bc000은 "TP-Processor75"스레드를 식별하므로 덤프 내의 동일한 스레드에 대해 여러 번 언급 할 예정입니까? – Oliver
글쎄 0x00000000472bc000은 스레드가 입력 대기중인 모니터를 나타냅니다. 다른 스레드가 모니터 참조 0x00000000472bc000을 입력했으며 TP-Processor75가 현재 보유 스레드가 0x00000000472bc000을 릴리스 할 때까지 기다리고 있습니다. –