我的网页应用程序标题中有一个搜索框,并使用自动填充功能帮助用户按作者姓名或图书标题查找图书。在用户输入时,oninput()
函数通过FindBooks
调用servlet ajax
。 FindBooks
servlet调用类suggest()
的静态方法SuggestionBook
,它返回与输入字符串匹配的书籍数组。
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);
}
我在类static
中使用了SuggestionBook.java
方法,以避免为每个应用程序会话加载数据。因此它只会加载一次,然后可以由不同的会话共享。但由于静态方法只有一个副本,并且所有会话都使用相同的static
方法来获取数据。他们是否必须等待其他会话正在使用该方法,或者所有会话可以同时访问它?如果是,它是否会影响应用程序的性能。如果否,JVM如何管理单个副本的并发访问?最后,根据我的理解,只要类SuggestionBook
不是垃圾回收,数据就会保留在内存中。将数据结构用作class variables
而不是instance variables
是否正确,因为它们会在更长的时间内阻止可用内存。
答案 0 :(得分:4)
他们是否必须等待其他会话正在使用该方法,否则所有会话都可以同时访问它?
不,他们不必等待,是的,他们可以同时访问。
同时从多个会话访问同一个对象可以是a 问题,但不一定是。例如,如果两个会话执行 同时访问对象而不改变其状态 精细。如果他们确实改变了状态并且状态转换涉及不稳定 中间状态可能会出现问题。
如果两个线程同时运行相同的方法,则它们的代码指针都指向该方法,并在其堆栈上拥有自己的参数和局部变量副本。如果堆栈上的东西指向堆上的相同对象,它们只会相互干扰。
如果是,是否会影响应用程序的性能。如果否,JVM如何管理单个副本的并发访问?
java中的内存分为两类 - 堆和堆栈。堆是所有对象都存在的地方,堆栈是线程工作的地方。每个线程都有自己的堆栈,无法访问其他堆栈。每个线程还有一个指向代码的指针,指向它们当前正在运行的代码位。当一个线程开始运行一个新方法时,它会将该方法中的参数和局部变量保存在自己的堆栈中。其中一些值可能是指向堆上对象的指针。
最后,根据我的理解,只要类SuggestionBook没有被垃圾收集,数据就会保留在内存中。将数据结构用作类变量而不是实例变量是一种正确的方法,因为它们会在较长时间内阻塞可用内存。
由于您正在使用servlet,因此在webapp启动时只创建一个servlet实例,并在所有请求之间共享。静态与否,每个类/实例变量将在所有请求/会话之间共享。 Servlet只有一个实例,实例变量就像一个静态变量。因此,不要求人们通过使变量静态而不是实例来了解单个实例(因为许多人不知道),而是消除了使用中的任何混淆。因此,变量的意图更清晰,不太可能被误解。所以,可用性并不是一个糟糕的方法。
答案 1 :(得分:0)
您可以将建议方法设为同步,它会起作用。因为只有第一个被调用才会填充树中的数据,后续调用才会读取它。
但是如果你同步suggest方法,那么调用建议的每个线程都会被同步,这是不必要的,因为第一次调用已经填满了树。
解决方案1)创建一个静态块并初始化该树。这样,只要加载类就会初始化树。
解决方案2)使“fillTernary”方法同步,并且在方法内部仅在未初始化树时初始化树,即if(isTernaryEmpty)。请注意,两种方法都需要if条件,以防止多个线程同时初始化。