[
https://issues.apache.org/jira/browse/NETBEANS-106?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16224510#comment-16224510
]
lbruun edited comment on NETBEANS-106 at 10/30/17 8:43 AM:
-----------------------------------------------------------
Below is a NetBeans centric example which shows off the problem. Success of the
new enhanced NB classloader (my proposal) can be measured by the below code no
longer causing NB to freeze.
{code:java}
/**
* Example which shows how NetBeans freezes because of deadlock.
* (NETBEANS-58 and JDK-8068184)
*
* Instructions: Add the following to a module and you'll see all of NetBeans
* freezing shortly after the UI is shown.
*
* In order to be as realistic as possible the case is shown via use of
* a custom Authenticator. This is really unnecessary but makes it a
* bit more like real-life.
*
* @author lbruun
*/
@OnStart
public class NetworkTaskStarter implements Runnable {
private static URL TEST_URL;
private static InetAddress IP4;
static {
try {
TEST_URL = new URL("https://protected.apache.org/foo/bar/foo2");
IP4 = InetAddress.getByAddress(new byte[]{-44, 110, -89, -99}); //
212.110.167.157
} catch (UnknownHostException | MalformedURLException ex) {
}
}
private final RequestProcessor rp = new RequestProcessor("FreezeTesterRP",
2);
@Override
public void run() {
rp.post(new Runnable() {
@Override
public void run() {
try {
// Lots of cerimony to wait for UI to be ready
FutureTask<Void> uiInit = new FutureTask<>(new
Callable<Void>() {
@Override
public Void call() throws Exception {
return null;
}
});
WindowManager.getDefault().invokeWhenUIReady(uiInit);
uiInit.get();
// Install our own Authenticator
Authenticator.setDefault(new CustomAuthenticator());
// Fire our simulated network task
rp.post(new NetworkTaskSimulator());
} catch (InterruptedException | ExecutionException ex) {
Exceptions.printStackTrace(ex);
}
}
});
}
private class NetworkTaskSimulator implements Runnable {
@Override
public void run() {
// Call the Authenticator the same way as the JDK's
// URLConnection classes do : with a lock on the CL !
synchronized (Thread.currentThread().getContextClassLoader()) {
Authenticator.requestPasswordAuthentication(
"squid.chicago.internal.net", // host
IP4, // addr
3128, // port
"https", // protocol
"", // prompt (aka realm)
"negotiate", // scheme
TEST_URL, // URL
Authenticator.RequestorType.PROXY
);
// We never get here. Application deadlocks above.
}
}
}
public class CustomAuthenticator extends Authenticator {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// Do something which requires classloading and which executes
// on a different thread and then waits for the result. It can be
// anything really, but Keyring.read() is the simplest way of
showing
// the problem. So we use that.
// (Another typical example is launching a dialog on the Swing EDT
// and then waiting for the user's input to that dialog)
Keyring.read("foobar"); // trigger the deadlock
return null;
}
}
}
{code}
was (Author: lbruun):
Below is a NetBeans centric example which shows off the problem. Success of the
new enhanced NB classloader (my proposal) can be measured by the below code no
longer causing NB to freeze.
{code:java}
/**
* Example which shows how NetBeans freezes because of deadlock.
* (NETBEANS-58 and JDK-8068184)
*
* Instructions: Add the following to a module and you'll see all of NetBeans
* freezing shortly after the UI is shown.
*
* In order to be as realistic as possible the freeze is shown via
* use of a custom Authenticator. This is really unnecessary but makes it
* a bit more like real-life.
*
* @author lbruun
*/
@OnStart
public class NetworkTaskStarter implements Runnable {
private static URL TEST_URL;
private static InetAddress IP4;
static {
try {
TEST_URL = new URL("https://protected.apache.org/foo/bar/foo2");
IP4 = InetAddress.getByAddress(new byte[]{-44, 110, -89, -99}); //
212.110.167.157
} catch (UnknownHostException | MalformedURLException ex) {
}
}
private final RequestProcessor rp = new RequestProcessor("FreezeTesterRP",
2);
@Override
public void run() {
rp.post(new Runnable() {
@Override
public void run() {
try {
// Lots of cerimony to wait for UI to be ready
FutureTask<Void> uiInit = new FutureTask<>(new
Callable<Void>() {
@Override
public Void call() throws Exception {
return null;
}
});
WindowManager.getDefault().invokeWhenUIReady(uiInit);
uiInit.get();
// Install our own Authenticator
Authenticator.setDefault(new CustomAuthenticator());
// Fire our simulated network task
rp.post(new NetworkTaskSimulator());
} catch (InterruptedException | ExecutionException ex) {
Exceptions.printStackTrace(ex);
}
}
});
}
private class NetworkTaskSimulator implements Runnable {
@Override
public void run() {
// Call the Authenticator the same way as the JDK's
// URLConnection classes do : with a lock on the CL !
synchronized (Thread.currentThread().getContextClassLoader()) {
Authenticator.requestPasswordAuthentication(
"squid.chicago.internal.net", // host
IP4, // addr
3128, // port
"https", // protocol
"", // prompt (aka realm)
"negotiate", // scheme
TEST_URL, // URL
Authenticator.RequestorType.PROXY
);
// We never get here. Application deadlocks above.
}
}
}
public class CustomAuthenticator extends Authenticator {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// Do something which requires classloading and which executes
// on a different thread and then waits for the result. It can be
// anything really, but Keyring.read() is the simplest way of
showing
// the problem. So we use that.
// (Another typical example is launching a dialog on the Swing EDT
// and then waiting for the user's input to that dialog)
Keyring.read("foobar"); // trigger the deadlock
return null;
}
}
}
{code}
> NB classloaders should use fine grained locking
> -----------------------------------------------
>
> Key: NETBEANS-106
> URL: https://issues.apache.org/jira/browse/NETBEANS-106
> Project: NetBeans
> Issue Type: Bug
> Reporter: lbruun
>
> In order to avoid issues such as NETBEANS-58 the NB classloaders should use
> fine grained locking. (possibly only needed on System Classloader)
> Background: At the time when the NB classloaders were created the general
> consensus at the time was that a proper classloader used locking at the level
> of the classloader itself. This was also how the classloaders in the JDK
> worked. However, in Java 7 this
> [changed|https://docs.oracle.com/javase/7/docs/technotes/guides/lang/cl-mt.html].
> The JDK classloaders started using more fine grained locking. But the NB
> classloaders didn't follow suit. (it is not exactly an inheritable feature)
> This means we are now in a situation were deadlocks occur in NB code which
> cannot be reproduced with only the JDK. One such case is JDK-8068184 which
> causes a severe freeze in NetBeans. We cannot expect the JDK folks to fix
> problems that occur only in NB code.
> What I propose is that a more fine grained locking mechanism is used. Look to
> the JDK for inspiration. This will solve such deadlock issues. I don't think
> it is necessary to actually claim that it is now fully multi-thread safe by
> calling
> [registerAsParallelCapable()|https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#registerAsParallelCapable()].
> This can be left for a later exercise. First step is to remove the lock on
> the classloader as a whole.
> NETBEANS-58 contains a simple [minimal
> example|https://issues.apache.org/jira/browse/NETBEANS-58?focusedCommentId=16224149&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-16224149]
> which can be used as a measure of success. Once an NB application can use
> the pattern in the example without freezing then we have accomplished the
> goal.
>
> (I'm personally not confident with fiddling with the NB classloaders. Scares
> the sh.. out of me because I know it is the heart of the platform. So won't
> come up with a PR. Sorry.)
--
This message was sent by Atlassian JIRA
(v6.4.14#64029)