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_Variables_Static - Fatal编程技术网

如何使用静态变量和线程提高Java性能?

如何使用静态变量和线程提高Java性能?,java,multithreading,performance,variables,static,Java,Multithreading,Performance,Variables,Static,为了不深入探讨我的软件应该做什么,让我举一个例子,说明我正在尝试解决的问题,让这个简短而甜蜜 假设我有一个名为X的基类和该类的一个实现,我将调用Y。类Y自然地扩展了基类X。假设我有20个对象,它们将通过一个单独的线程为每个对象实例化类Y,每次实例化都会将一个大文件加载到内存中。这些对象中的一些可能需要使用不同的文件,但为了简单起见,假设它们都需要访问同一个文件 有没有办法定义一个特定的对象(变量),在基类中静态地指向这些文件,这样即使实现类通过20个不同的线程加载了20次,它们都可以共享同一个静

为了不深入探讨我的软件应该做什么,让我举一个例子,说明我正在尝试解决的问题,让这个简短而甜蜜

假设我有一个名为X的基类和该类的一个实现,我将调用Y。类Y自然地扩展了基类X。假设我有20个对象,它们将通过一个单独的线程为每个对象实例化类Y,每次实例化都会将一个大文件加载到内存中。这些对象中的一些可能需要使用不同的文件,但为了简单起见,假设它们都需要访问同一个文件

有没有办法定义一个特定的对象(变量),在基类中静态地指向这些文件,这样即使实现类通过20个不同的线程加载了20次,它们都可以共享同一个静态对象,这样文件只需要加载一次

提前感谢您的帮助…

您可以使用开始

将映射的键设为字符串,该值应为加载的表示形式所必须的值

请注意,如果更改加载的文件数据,即使使用ConcurrentHashMap,仍然需要确保线程安全

在创建对象之前初始化此映射,并将其传递给对象的构造函数

  • 那个文件是只读的吗
  • 这是一大串数据吗 如果是这样,那么一个
    字符串
    只需将其设置为
    受保护的静态最终字符串
    ,它是线程安全的。如果它是可变的,那么在你的未来,你会受到全世界的伤害

    如果它是一个二进制文件,并且只能以只读方式使用,那么您可能可以使用
    字节[]
    来代替
    字符串
    ,并确保不让任何内容更改数组中的字节。更好的方法是以只读方式实现一些
    读取器
    接口

    使线程安全的最简单和最安全的方法是使其不可变。
    final
    关键字使引用不可变,但不会使它指向的对象不可变。由于
    字符串
    是不可变的,
    final
    使引用也不可变,因此您可以继续使用。如果您需要所有线程之间共享更改的可变性,那么
    java.util.concurrent
    包将是您的朋友


    如果将变量
    protected static final
    设置为final,则子类的所有实例(无论它们在哪个执行线程上)都将看到数据。

    如果您提前知道该文件,则可以在静态初始值设定项块中打开并加载该文件,并将内容存储在静态数据成员中。然后,该类的所有实例都可以访问该内容,而不管当前哪个线程正在访问实例对象

    // In the base class
    protected static final String fileContents;
    
    static {
        fileContents = readStuffFromFile();
    }
    

    一个非静态的内部类将满足您的所有愿望:

    public class Foo {
      protected String member;
      public Foo(String member) {
        this.member = member;
      }
      public class Bar {
        protected String member;
        public Bar(String member) {
          this.member = member;
        }
        public void show() {
          System.out.println("this.member: " + this.member + "; Foo.this.member: " + Foo.this.member);
        }
      }
      public static void main(String[] args) throws javax.mail.MessagingException, java.io.IOException {
        Foo foo_a = new Foo("a");
        Foo foo_b = new Foo("b");
        Bar bar_a1 = foo_a.new Bar("1");
        Bar bar_a2 = foo_a.new Bar("2");
        Bar bar_b1 = foo_b.new Bar("1");
        Bar bar_b2 = foo_b.new Bar("2");
        bar_a1.show();
        bar_a2.show();
        bar_b1.show();
        bar_b2.show();
      }
    }
    
    好吧,好吧,好吧(-2票后):

    首先,上述解决方案都没有解决原始问题的一部分,即可能没有一个文件被所有对象共享。一组对象可能需要共享文件A,另一组对象可能需要共享文件B,以此类推。上面的内部类解决方案正是为了满足这个需求。每个文件/组实例化一次外部类,并从同一外部对象实例化组的内部对象

    其次,静态是一个糟糕的选择:很可能需要在运行时而不是在程序启动时指定文件。上面的外部/内部类结构正好解决了这个问题。只要需要,就可以实例化外部类。不需要静态初始化(也不需要任何复杂的延迟静态初始化方案)

    第三,线程偏执症根本不是这个问题(或这个解决方案)中的一个问题。很明显,该文件是只读的,因此是不可变的,因此在这个问题上进行所有并发操作只会降低优雅解决方案的效果

    最后,说到优雅,这是,而且可能是唯一的一个


    此更新主要针对新来查看线程的人,因为此线程中的负面投票者可能会将其设置为-5。

    创建一个单独的对象来存储文件的缓存内容。

    通过同步使此对象成为线程安全的,以便多个线程可以访问此对象。在基类X中,放置对此对象的引用。现在,可以用同一个缓存对象实例化类X的多个实例。现在,这要求每个文件只加载一次该对象,并且可以根据需要在任意多个X/Y对象之间共享该对象

    剩下的唯一问题是有一种加载这些文件的方法。这个问题的解决方案将取决于应用程序和这些文件的结构,但我将提供一个可能的解决方案

    创建一个factory类,该类将创建此新类型的对象。此工厂将在其自己的线程上运行,所有加载的文件都将通过此工厂加载。创建一个可以从此工厂请求文件的接口。工厂保留对所有已加载文件的引用,因此如果已加载,它可以立即返回引用。未加载时,使用与此文件相关的工厂中存储的占位符对象上的
    Object.wait()
    阻止调用线程。工厂加载完文件后,在该文件的占位符对象上调用
    Object.notifyAll()
    ,该占位符对象将唤醒每个线程,这些方法将返回对加载文件的引用

    完成后,需要文件的每个线程都可以调用工厂中的方法来获取文件对象。这个线程现在将阻塞,直到文件对象被加载,然后函数将ret