Try to load accessClass without synchronization

In EsotericSoftware/kryo#422 it's reported that the sychronization
in `ConstructorAccess.get` on the loader is causing significant
thread contention.
This change tries to prevent this, via double checked locking.
Because it's the same pattern it's also done for `FieldAccess`
and `MethodAccess` as well.
This commit is contained in:
Martin Grotzke 2016-05-08 22:44:25 +02:00
parent 88ec7037ea
commit c5563b1205
3 changed files with 232 additions and 220 deletions

View File

@ -51,10 +51,13 @@ public abstract class ConstructorAccess<T> {
Class accessClass; Class accessClass;
AccessClassLoader loader = AccessClassLoader.get(type); AccessClassLoader loader = AccessClassLoader.get(type);
synchronized (loader) {
try { try {
accessClass = loader.loadClass(accessClassName); accessClass = loader.loadClass(accessClassName);
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
synchronized (loader) {
try {
accessClass = loader.loadClass(accessClassName);
} catch (ClassNotFoundException ignored2) {
String accessClassNameInternal = accessClassName.replace('.', '/'); String accessClassNameInternal = accessClassName.replace('.', '/');
String classNameInternal = className.replace('.', '/'); String classNameInternal = className.replace('.', '/');
String enclosingClassNameInternal; String enclosingClassNameInternal;
@ -100,6 +103,7 @@ public abstract class ConstructorAccess<T> {
accessClass = loader.defineClass(accessClassName, cw.toByteArray()); accessClass = loader.defineClass(accessClassName, cw.toByteArray());
} }
} }
}
ConstructorAccess<T> access; ConstructorAccess<T> access;
try { try {
access = (ConstructorAccess<T>)accessClass.newInstance(); access = (ConstructorAccess<T>)accessClass.newInstance();

View File

@ -121,10 +121,13 @@ public abstract class FieldAccess {
Class accessClass = null; Class accessClass = null;
AccessClassLoader loader = AccessClassLoader.get(type); AccessClassLoader loader = AccessClassLoader.get(type);
synchronized (loader) {
try { try {
accessClass = loader.loadClass(accessClassName); accessClass = loader.loadClass(accessClassName);
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
synchronized (loader) {
try {
accessClass = loader.loadClass(accessClassName);
} catch (ClassNotFoundException ignored2) {
String accessClassNameInternal = accessClassName.replace('.', '/'); String accessClassNameInternal = accessClassName.replace('.', '/');
String classNameInternal = className.replace('.', '/'); String classNameInternal = className.replace('.', '/');
@ -155,6 +158,7 @@ public abstract class FieldAccess {
accessClass = loader.defineClass(accessClassName, cw.toByteArray()); accessClass = loader.defineClass(accessClassName, cw.toByteArray());
} }
} }
}
try { try {
FieldAccess access = (FieldAccess)accessClass.newInstance(); FieldAccess access = (FieldAccess)accessClass.newInstance();
access.fieldNames = fieldNames; access.fieldNames = fieldNames;

View File

@ -107,10 +107,13 @@ public abstract class MethodAccess {
Class accessClass; Class accessClass;
AccessClassLoader loader = AccessClassLoader.get(type); AccessClassLoader loader = AccessClassLoader.get(type);
synchronized (loader) {
try { try {
accessClass = loader.loadClass(accessClassName); accessClass = loader.loadClass(accessClassName);
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
synchronized (loader) {
try {
accessClass = loader.loadClass(accessClassName);
} catch (ClassNotFoundException ignored2) {
String accessClassNameInternal = accessClassName.replace('.', '/'); String accessClassNameInternal = accessClassName.replace('.', '/');
String classNameInternal = className.replace('.', '/'); String classNameInternal = className.replace('.', '/');
@ -272,6 +275,7 @@ public abstract class MethodAccess {
accessClass = loader.defineClass(accessClassName, data); accessClass = loader.defineClass(accessClassName, data);
} }
} }
}
try { try {
MethodAccess access = (MethodAccess)accessClass.newInstance(); MethodAccess access = (MethodAccess)accessClass.newInstance();
access.methodNames = methodNames; access.methodNames = methodNames;