2011-10-19 114 views
0

我有这样的代码:多线程会导致程序停止?

public void GenerateWtW() { 
     ExecutorService exec = Executors.newFixedThreadPool(30); 

     ConcurrentHashMap<String, Double> tf_idfCache = new ConcurrentHashMap<String, Double>(); 
     ArrayList<String> allwords = getAllWords(); 
     int no_docs = getNumberOfDocs(); 

     int cnt = 0; 
     for (int i = 0; i < allwords.size(); i++) { 
      String word1 = allwords.get(i); 
      if (i < allwords.size() - 1) { 
       for (int j = i + 1; j < allwords.size(); j++) { 
        String word2 = allwords.get(j); 
        cnt++; 
        if (word1.equals(word2)) { 
         continue; 
        } 

        //System.out.println("[" + cnt + "] WtW Started: " + word1 + "," + word2 + " No of Docs: " + no_docs + " Total No of words: " + allwords.size()); 
        WTWThread t = new WTWThread(tf_idfCache, word1, word2, this, no_docs, db); 
        exec.execute(t); 

       } 
      } 
     } 
     exec.shutdown(); 
    } 

这里是线程的代码:

private static class WTWThread implements Runnable { 

     private ConcurrentHashMap<String, Double> cacheRef; 
     private String word1, word2; 
     private WordRank workRankInstance; 
     private int no_docs; 
     private Database db; 

     public WTWThread(ConcurrentHashMap<String, Double> cacheRef, String word1, String word2, WordRank workRankInstance, int no_docs, Database db) { 
      this.cacheRef = cacheRef; 
      this.word1 = word1; 
      this.word2 = word2; 
      this.workRankInstance = workRankInstance; 
      this.no_docs = no_docs; 
      this.db = db; 
     } 

     @Override 
     public void run() { 
      double sum = 0; 

      for (int i = 1; i <= 10; i++) { 
       Double tf_idf1 = cacheRef.get(word1 + i); 
       if (tf_idf1 == null) { 
        tf_idf1 = workRankInstance.getTF_IDF(word1, i); 
        cacheRef.put(word1 + i, tf_idf1); 
       } 
       Double tf_idf2 = cacheRef.get(word2 + i); 
       if (tf_idf2 == null) { 
        tf_idf2 = workRankInstance.getTF_IDF(word2, i); 
        cacheRef.put(word2 + i, tf_idf2); 
       } 
       sum = sum + (tf_idf1 * tf_idf2); 
      } 
      double wtw = sum/no_docs; 
      String query = "INSERT INTO wtw(word1,word2,wtw) VALUES(?,?,?);"; 
      try { 
       PreparedStatement ps = db.getConnection().prepareStatement(query); 
       ps.setString(1, word1); 
       ps.setString(2, word2); 
       ps.setDouble(3, wtw); 
       ps.executeUpdate(); 
       ps.close(); 
      } catch (SQLException ex) { 
       Logger.getLogger(WordRank.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } 

我的一切看起来不错,但这里是发生了什么,当我运行该程序,它处理的第一几百,然后突然停止!我检查了系统监视器,java进程在内存使用中开始增长,并达到约1Gb,然后没有任何反应。我想也许这是因为我有太多的线程,我尝试了4线程,但同样的事情发生。然后,我想也许我应该在创建线程之前使用sleep(),并且它确实解决了问题,它像一个魅力一样工作,但即使睡眠(1)也会让程序非常慢!我检查了我能想到的所有可能的事情!有什么我在这里失踪?

回答

0

你有几个词,你有多少RAM,这个程序在做什么?

你的tf_idfCache会变得非常大,增长至少与文字数量成正比,相当稳定的因素(你为每个单词放了10件东西来缓存),这可能会导致性能问题。

最后你确实有一个并发问题,但我不认为它会导致锁定。在代码

Double tf_idf1 = cacheRef.get(word1 + i); 
if (tf_idf1 == null) { 
    tf_idf1 = workRankInstance.getTF_IDF(word1, i); 
    cacheRef.put(word1 + i, tf_idf1); 
} 

你不能保证你不会计算两次排名。

我不认为线程数量导致任何问题,但你可能有一些其他并发问题导致锁(如果锁定,而不是内存开销是一个问题)。

+0

这不是堆空间问题,我将2gb分配给堆。问题是线程增长如此之快,我认为jvm无法处理它!因为我说,然后我放了一个延迟之前,一切工作正常!没有内存泄漏,没有锁定的情况。我认为我需要对线程池做些什么 – Tohid

+0

你不是在创建线程,而是在创建Runnable对象,它应该分布在固定数量的线程中(在你的例子中为30)。他们可能在完成工作后不久收集垃圾。 – Slartibartfast

0

听起来就像是要么出现OutOfMemoryError,要么程序实际上并没有停止,但由于内存使用情况,程序并未因磁盘交换而停止,而是暂停。 1 GiB相当多。找出是否有内存泄漏,可能是使用分析器。任何最近的JDK都与JVisualVM捆绑在一起。

+0

正如我所说,如果我把睡眠()之前,线程调用它工作正常!我可能会遇到一些性能问题,但我不认为有任何泄漏问题。 – Tohid