2011-10-19 148 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