【问题标题】:Using static method and variables in java web application在 Java Web 应用程序中使用静态方法和变量
【发布时间】:2015-03-02 19:44:26
【问题描述】:

我的 Web 应用程序的标题中有一个搜索框,并使用自动完成功能帮助用户按作者姓名或书名查找书籍。在用户输入时,oninput() 函数调用 servlet FindBooksajaxFindBooks servlet 调用 SuggestionBook 类的静态方法 suggest(),该方法返回与输入字符串匹配的书籍数组。

FindBooks.java

 JSONArray books = SuggestionBook.suggest(inputString);
 out.print(books);

SuggestionBook.java

 private static boolean isTernaryEmpty = true;
 private static Ternary ternary;

 private static void fillTernary() {
  // fills ternary search tree with data.
  isTernaryEmpty = false;
 }

 public static JSONArray suggest(String searchString) {
  if(isTernaryEmpty) {
    fillTernary();
  }
  return ternary.find(searchString);
 } 

我在SuggestionBook.java 类中使用了static 方法,以避免为应用程序的每个会话加载数据。所以它只会被加载一次,然后可以被不同的会话共享。但是由于静态方法只有一个副本,并且所有会话都使用相同的static 方法来获取数据。当其他会话正在使用该方法时,他们是否必须等待,或者所有会话都可以同时访问它?如果是,是否会影响应用程序的性能。如果否,JVM 如何管理单个副本的并发访问?最后,根据我的理解,只要类SuggestionBook 未被垃圾收集,数据就会保留在内存中。将数据结构用作class variables 而不是instance variables 是正确的方法吗,因为它们会阻塞可用内存更长的时间。

【问题讨论】:

  • 请学习how to accept an answer 如果答案没有帮助,您可以发表评论,要求该人提供更多说明。

标签: java web-applications autocomplete static


【解决方案1】:

当其他会话正在使用该方法时,他们是否必须等待,或者它可以被所有会话同时访问?

不,它们不必等待,是的,它们可以同时访问。

同时从多个会话访问同一个对象可能是 问题,但不是必须的。例如,如果两个会话执行 同时访问一个对象而不改变它的状态 美好的。如果他们确实改变了状态并且状态转换涉及不稳定 中间状态可能会出现问题。

如果两个线程同时运行同一个方法,它们的代码指针都会指向该方法,并且在它们的堆栈上都有自己的参数和局部变量副本。只有当它们的栈中的东西指向堆上的相同对象时,它们才会相互干扰。

如果是,是否会影响应用程序的性能。如果否,这个单副本的并发访问是如何被JVM管理的?

java中的内存分为两种——堆和栈。堆是所有对象所在的地方,堆栈是线程工作的地方。每个线程都有自己的堆栈,并且不能访问彼此的堆栈。每个线程还有一个指向代码的指针,该指针指向它们当前正在运行的代码位。当一个线程开始运行一个新方法时,它将该方法中的参数和局部变量保存在自己的堆栈中。其中一些值可能是指向堆上对象的指针。

最后,根据我的理解,只要类 SuggestionBook 没有被垃圾收集,数据就会留在内存中。将数据结构用作类变量而不是实例变量是否正确,因为它们会阻塞可用内存更长的时间。

由于您使用的是 servlet,因此单个 servlet 实例仅在 webapp 启动时创建一次,并在所有请求之间共享。无论是否静态,每个类/实例变量都将在所有请求/会话之间共享。 Servlet 将只有一个实例,并且实例变量的作用类似于静态变量。因此,与其通过将变量设为静态而不是实例来要求人们了解单个实例(因为很多人不知道),它消除了使用中的任何混淆。因此,变量的意图更清晰,更不容易被误解。所以是的,从可用性来看,这不是一个糟糕的方法。

【讨论】:

    【解决方案2】:

    您可以将建议方法设为同步,它会起作用。因为只有第一个调用会填充树中的数据,后续调用只会读取它。

    但是如果你同步建议方法,每个调用建议的线程都会被同步,这是不必要的,因为第一次调用已经填满了树。

    解决方案 1) 创建一个静态块并在其中初始化树。这样一来,类一加载,树就会被初始化。

    解决方案 2) 使“fillTernary”方法同步,并在方法内部仅在树未初始化时才初始化树,即 if(isTernaryEmpty)。请注意,这两种方法都需要if条件,以防止多个线程同时初始化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2012-11-24
      • 1970-01-01
      • 2013-05-18
      • 1970-01-01
      • 1970-01-01
      • 2013-10-07
      相关资源
      最近更新 更多