Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 识别源自超类的方法调用的快速线程安全方法 让我们考虑第三方类 < ,其特征如下:_Java_Multithreading_Performance_Inheritance - Fatal编程技术网

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();
            }
        }