Java 识别源自超类的方法调用的快速线程安全方法 让我们考虑第三方类 < ,其特征如下:
它的大部分实现都是私有的,而且相当复杂,因此可以对其进行扩展,但不能进行合理的修改Java 识别源自超类的方法调用的快速线程安全方法 让我们考虑第三方类 < ,其特征如下:,java,multithreading,performance,inheritance,Java,Multithreading,Performance,Inheritance,它的大部分实现都是私有的,而且相当复杂,因此可以对其进行扩展,但不能进行合理的修改 A有一个非常昂贵的构造函数,永远不应该不必要地调用它——在我的例子中,它构建了一个庞大的数据查找表供以后使用 这意味着创建一个作为a的插入式替换是不可能的,因为任何装饰器都必须从a继承并调用其构造函数 A由第三方代码使用,因此A不能代替它使用-其他代码需要A的实例,这是它应该得到的 A提供了一系列非常昂贵的报告方法,这些方法需要经过大量的争论才能生成一系列报告 这些方法不会产生任何本地使用的结果-理论上它们可能是
A
有一个非常昂贵的构造函数,永远不应该不必要地调用它——在我的例子中,它构建了一个庞大的数据查找表供以后使用
这意味着创建一个作为a
的插入式替换是不可能的,因为任何装饰器都必须从a
继承并调用其构造函数A
由第三方代码使用,因此A不能代替它使用-其他代码需要A
的实例,这是它应该得到的A
提供了一系列非常昂贵的报告方法,这些方法需要经过大量的争论才能生成一系列报告
这些方法不会产生任何本地使用的结果-理论上它们可能是异步的,但不幸的是它们不是A
的方法相互调用-很多A
实现是不透明的,在不断变化的情况下,像使用反射后实例化(reflection post-instantiation)这样的黑客行为是不可能的A
不是线程安全的-不是真的a
成为了一个瓶颈,因此我创建了一个子类B
,希望将实际的包装碎片推到一个单独的线程中。我覆盖了A
的所有公共方法,只将Runnable
对象提交给单线程执行器服务。每个Runnable
然后从工作线程执行相应的super
方法
不幸的是,A
经常调用自己的公共方法。通常这不会是一个问题,但在我的例子中,超类正在从B
调用方法。这是一个主要问题,因为B
方法推迟了实际执行,并将新任务提交给executor服务,从而导致性能和正确性问题
我的解决方案是检查B
中所有方法的结果,这样来自工作线程的调用将直接委托给super
方法,而不是作为新任务提交
因此,现在我已经到了Thread.currentThread()
成为性能问题的地步,这可能是因为它是一个被频繁调用的本机方法
- 是否有更快的方法以线程安全的方式检查源自超类和/或工作线程的方法调用
- 有没有另一种设计可以让我将
的包装碎片推到另一个线程上?在我看来,由于A
是第三方代码,我几乎被困在了A
- 因为
A
不是线程安全的,用不同的线程调用它是不安全的。。。安全的
想法:
- 您可以将
的实例池化,也就是说,每当线程需要A时,它都会从池中获取一个A(如果池为空,则创建一个),使用它,然后将其放回池中。这样,您将同时拥有所需的任意多个实例A
- 您可以修补
以跨实例缓存“巨大的查找表”(当然,这要求它是线程安全的,但如果表仅在构造后读取,则情况很简单),并在每个线程中使用A
的新实例A
您可以将
Thread.currentThread
替换为。
只需将例如Boolean
设置为ThreadLocal
,如果设置了(在输入方法时检查),则不生成新线程,而是在同一线程上执行
更新使用hashmap保留方法调用的跟踪。进入方法后,请检查hashmap中是否存在该方法(该方法的名称作为键)。
如果该方法不存在,则将其放入hashmap中,并使用后台线程调用该方法。
如果它存在,那么您必须已经在后台线程中。因此,在同一个线程中进行调用如果您的运行时环境允许使用自定义类加载器,您应该能够使用使用反射调用原始类A的自定义委托类替换第三方类A 下面是代理类A的一个示例:
package fi.test;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ClassA {
private static final Class<?> clazz;
private static final Method doSomething;
private Object instance;
static {
ClassLoader classLoader = new ClassLoader(ClassA.class.getClassLoader()) {
@Override
public synchronized Class<?> loadClass(String name)
throws ClassNotFoundException {
if (!name.equals(ClassA.class.getName())) {
return super.loadClass(name);
}
Class<?> clazz = findLoadedClass(name);
if (clazz == null) {
// The original class A is stored as ClassA.class.orig
InputStream inputStream = getParent().getResourceAsStream(
"fi/test/ClassA.class.orig");
try {
byte[] buffer = new byte[100000];
int length = inputStream.read(buffer);
clazz = defineClass(name, buffer, 0, length);
} catch (IOException exception) {
throw new ClassNotFoundException("", exception);
} finally {
try {
inputStream.close();
} catch (IOException exception) {
}
}
}
return clazz;
}
};
try {
// Class A
clazz = classLoader.loadClass(ClassA.class.getName());
// Do something
doSomething = clazz.getMethod("doSomething", new Class<?>[0]);
} catch (Exception exception) {
throw new Error(exception);
}
}
public ClassA() {
try {
instance = clazz.newInstance();
} catch (InstantiationException exception) {
throw new RuntimeException(exception);
} catch (IllegalAccessException exception) {
throw new RuntimeException(exception);
}
}
public void doSomething() {
try {
doSomething.invoke(instance, new Object[0]);
} catch (IllegalAccessException exception) {
throw new RuntimeException(exception);
} catch (InvocationTargetException exception) {
throw new RuntimeException(exception);
}
}
}
这是我用来测试委托的类:
package fi.test;
public class Tester {
public static void main(String[] args) {
ClassA instance = new ClassA();
instance.doSomething();
}
}
什么是“本地使用的结果”(local to What?)以及这与异步有什么关系(你是说线程安全吗?)@meriton:我的意思是报告方法调用是fire and forget。我不必等待他们完成…
Thread.currentThread()
非常快,怎么会有问题?特别是在假定的非常昂贵的操作之前调用一次,它不应该被注意到。@unreputable:问题是非常昂贵的操作调用了A
中的其他公共方法数千次。由于这些方法也被其他类使用,我不能直接委托给super
-我必须检查调用是否应该提交给工作线程。因为ThreadLocal.get()
调用thread.currentThread()
,与直接比较currentThread相比,为什么这会提高性能?@meriton:是吗?我认为这是一个基于thread的hashmapids@Cratylus:如何在不调用thread.currentThread()的情况下获取线程名称
?@thkala:当您第一次调用a
的方法创建线程时,给它一个名称。将该名称存储在哈希表中。您不需要获取na
package fi.test;
public class Tester {
public static void main(String[] args) {
ClassA instance = new ClassA();
instance.doSomething();
}
}