2013-07-26 21 views
4

我试图根据servlet请求中的数据创建多个输出文本数据文件。以我的servlet的约束条件是:具有多线程的Java Servlet

  • 我的servlet等待足够的请求产生一个文件
  • 否则一分钟后,它会超时并产生之前打一个阈值(在一个文件中,例如20名)文件

我写的代码是这样的:

  1. doGet不同步

  2. doGet我在创建一个新的线程池(原因是调用的应用程序到我的servlet不会发送下一个请求,直到我的servlet返回响应 - 所以我验证请求并返回即时确认返回以获取新的请求)

  3. 传过来的所有请求数据在一个新的线程池创建

  4. 调用同步函数来完成线程计算和文件

我使用wait(60000)打印线程。问题在于,代码在一分钟内生成了具有正确阈值(名称)的文件,但在一分钟超时后,生成的文件(极少数)的容量超过了,例如,名称多于我在容量。

我认为它与唤醒时引起问题的线程有关?

我的代码是

if(!hashmap_dob.containsKey(key)){ 
request_count=0; 
hashmap_count.put(key, Integer.toString(request_count)); 

sb1 = new StringBuilder(); 
sb2 = new StringBuilder(); 
sb3 = new StringBuilder(); 

hashmap_dob.put(key, sb1); 
hashmap_firstname.put(key, sb2);  
hashmap_surname.put(key, sb3); 
       } 

if(hashmap_dob.containsKey(key)){ 
    request_count = Integer.parseInt(hm_count.get(key)); 
    request_count++; 
    hashmap_count.put(key, Integer.toString(request_count)); 
    hashmap_filehasbeenprinted.put(key, Boolean.toString(fileHasBeenPrinted)); 
       } 


      hashmap_dob.get(key).append(dateofbirth + "-"); 
    hashmap_firstname.get(key).append(firstName + "-"); 
    hashmap_surname.get(key).append(surname + "-"); 


    if (hashmap_count.get(key).equals(capacity)){ 

     request_count = 0; 

    dob = hashmap_dob.get(key).toString(); 
    firstname = hashmap_firstname.get(key).toString(); 
    surname = hashmap_surname.get(key).toString(); 

    produceFile(required String parameters for file printing); 

    fileHasBeenPrinted = true; 
    sb1 = new StringBuilder(); 
    sb2 = new StringBuilder(); 
    sb3 = new StringBuilder(); 

    hashmap_dob.put(key, sb1); 
    hashmap_firstname.put(key, sb2); 
    hashmap_surname.put(key, sb3); 
    hashmap_count.put(key, Integer.toString(request_count)); 
    hashmap_filehasbeenprinted.put(key, Boolean.toString(fileHasBeenPrinted)); 
      } 
    try{ 

    wait(Long.parseLong(listenerWaitingTime)); 


     }catch (InterruptedException ie){ 
      System.out.println("Thread interrupted from wait"); 
      } 

    if(hashmap_filehasbeenprinted.get(key).equals("false")){ 

    dob = hashmap_dob.get(key).toString(); 
    firstname = hashmap_firstname.get(key).toString(); 
    surname = hm_surname.get(key).toString(); 

    produceFile(required String parameters for file printing); 

    sb1 = new StringBuilder(); 
    sb2 = new StringBuilder(); 
    sb3 = new StringBuilder(); 
    hashmap_dob.put(key, sb1); 
    hashmap_firstname.put(key, sb2); 
    hashmap_surname.put(key, sb3); 
    fileHasBeenPrinted= true; 
    request_count =0; 
    hashmap_filehasbeenprinted.put(key, Boolean.toString(fileHasBeenPrinted)); 

    hashmap_count.put(key, Integer.toString(request_count)); 
      } 

如果你有到这里,然后感谢您阅读我的问题,并在此先感谢,如果您有任何thougths它朝分辨率!

+0

仅供参考 - Camel外壳是Java变量通用的命名约定。 – Robin

+0

感谢提醒罗宾 – user2622263

回答

4

我没有看你的代码,但我觉得你的方法很复杂。试试这个:

  1. 创建一个BlockingQueue供数据使用。
  2. 在servlet中,将数据放入队列并返回。
  3. 在启动时创建一个单个工作线程,该线程以60秒的超时从队列中提取数据并将它们收集到列表中。
  4. 如果列表中包含足够的元素或发生超时,请编写一个新文件。

ServletContextListener中创建线程和队列。中断线程停止它。在线程中,当在队列中等待时收到InterruptedException时,将最后剩下的项目清除到文件中。

+0

好方法。但是这需要额外的后台线程才能运行来监视BLOCKING_QUEUE。一旦请求完成,Servlet将退出。那么你如何建议在Web应用程序本身中监视和处理BlockingQueue。 –

+0

在“ServletContextListener”中创建线程+队列。这样,你也可以干净地停止线程。 –

+0

我的猜测是他正在编写自己的服务器,所以他不会使用Java EE和ServletContextListener。但我认为他应该使用BlockingQueue和一个工作者线程。 – toto2

1

按我的理解,你要创建/在两种情况下产生一个新的文件:

  • 的请求数创下了预定阈值。
  • 阈值超时完成。

我建议如下:

  1. 使用的应用程序范围的变量:HttpServletRequest的含有对象requestMap。
  2. 在每个servlet命中时,只需将收到的请求添加到地图。
  3. 现在创建监听器/过滤器requestMonitor什么是合适的,来监视requestMap的值。
  4. RequestMonitor应该检查requestMap是否已经增长到预定义的阈值。
  5. 如果没有,那么它应该允许servlet添加请求对象。
  6. 如果有,那么它应该打印文件,清空requestMap,然后允许Servlet添加下一个请求。
  7. 对于超时,您可以使用APPLICATION_SCOPE中的LAST_FILE_PRODUCED变量来检查何时生成最后一个文件。这应该在每次生成文件时更新。
1

我想读你的代码,但是有很多的信息丢失,因此,如果您能提供更多的细节:

1)压痕被搞砸了,我不知道是否有在复制代码时引入了一些错误。

2)您发布的代码是什么? doGet之后在其他线程上调用的代码?

3)也许你也可以添加变量声明。那些线程安全类型(ConcurrentHashMap)?

4)我不确定我们有关于fileHasBeenPrinted的所有信息。此外,它似乎是一个布尔,它不是线程安全的。 5)你谈论“同步”功能,但你没有包括这些功能。

编辑

如果你复制的代码是一个同步的方法,这意味着如果你有很多的要求,只有一个永远只能运行在特定的时间。等待的60秒总是被调用(看起来缩进不太清楚,但我认为总是等待60秒,无论文件是否被写入)。因此,在另一个线程(请求)可以被处理之前,您将同步方法锁定60秒。这可以解释为什么在20次请求后你不写这个文件,因为超过20个请求可以在60秒内到达。

+0

谢谢托托....我对以下问题的回答如下: – user2622263

+0

1 - 由于数据敏感性,我手动尝试缩进并从原始代码更改了变量名称。很明显,我的缩进并没有奏效,所以对此感到抱歉。 – user2622263

+0

2 - 这是我的同步方法中的一个代码,我计算阈值并打印文件。该方法从doGet中调用。不过,正如我前面解释的,我已经从doGet创建了一个新的线程池,并且从该线程池中调用了此方法。 – user2622263