2012-11-22 29 views
1

我的多線程應用程序有一個創建多個線程的主類。主類將在啓動一些線程後等待。我創建的可運行類將獲得文件列表,獲取文件以及通過調用Web服務來刪除文件。線程完成後,它會通知主類再次運行。我的問題是它的工作了一段時間,但可能在一個小時左右後,它會從我在日誌中看到的輸出到達run方法的底部,就是這樣。 Java進程仍在運行,但根據我在日誌中查看的內容,它不會執行任何操作。爲什麼我的多線程應用程序暫停了?

主要類方法:

主要方法

while (true) { 

    // Removed the code here, it was just calling a web service to get a list of companies 

    // Removed code here was creating the threads and calling the start method for threads 

    mainClassInstance.waitMainClass(); 
} 

public final synchronized void waitMainClass() throws Exception { 
//  synchronized (this) { 
      this.wait(); 
//  } 
} 

public final synchronized void notifyMainClass() throws Exception { 
//  synchronized (this) { 
      this.notify(); 
//  } 
} 

本來我實例上的同步,但它改變的方法。 Web服務日誌或客戶端日誌中也沒有記錄錯誤。我的假設是我做了等待,並通知錯誤或我錯過了一些信息。

運行的線程代碼:

在run方法結束

// This is a class member variable in the runnable thread class 
mainClassInstance.notifyMainClass(); 

我之所以做了觀望,因爲我不想讓主類運行,除非有必要通知過程創建另一個線程。

主要類的目的是產生線程。這個類有一個無限循環來永遠創建和完成線程。

無限循環的目的是不斷更新公司名單。

+0

您是否添加了任何類型的日誌以瞭解發生了什麼? –

+0

請注意,只有在有線程在等待的情況下,通知纔有效。如果您的主線程還沒有完全等待,通知將落在地面上。 –

+3

你可能會用信號量做得更好。 –

回答

2

我建議從棘手的等待/通知轉移到Java平臺中的一個更高級別的併發設施。 ExecutorService可能提供開箱即用的功能。 (CountDownLatch也可以使用,但它更管道) 讓我們嘗試用你的代碼爲模板,勾畫一個例子:意見後

ExecutorService execSvc = Executors.newFixedThreadPool(THREAD_COUNT); 

while (true) { 

    // Removed the code here, it was just calling a web service to get a list of companies 
    List<FileProcessingTask> tasks = new ArrayList<FileProcessingTask>(); 
    for (Company comp:companyList) { 
     tasks.add(new FileProcessingTask(comp)); 
    } 
    List<Future<FileProcessingTask>> results = execSvc.invokeAll(tasks); // This call will block until all tasks are executed. 
    //foreach Future<FileProcessingTask> in results: check result 
} 

class FileProcessingTask implements Callable<FileResult> { // just like runnable but you can return a value -> very useful to gather results after the multi-threaded execution 
    FileResult call() {...} 
} 

------- ------編輯

如果您的getCompanies()電話可以同時爲您提供所有公司,並且不需要在處理過程中連續檢查該列表,則可以通過先創建所有工作項並一次提交給執行器服務來簡化流程。

List<FileProcessingTask> tasks = new ArrayList<FileProcessingTask>(); 
    for (Company comp:companyList) { 
     tasks.add(new FileProcessingTask(comp)); 
    } 

瞭解的重要一點是,ExecutorService的將使用所提供的集合作爲任務來執行的內部隊列中。它接受第一個任務,將其提供給池中的一個線程,收集結果,將結果放入結果集合中,然後接受隊列中的下一個任務。

如果您沒有生產者/消費者場景(cfr註釋),在執行任務(消耗)的同時生成新工作,則此方法應足以並行處理工作一個簡單的方法的線程數量。

如果您有額外的要求,爲什麼新工作的查找應該與工作處理交錯發生,您應該在問題中說清楚。

+0

使用此解決方案,我不希望等待所有線程完成,因爲一個線程可能需要10秒鐘,而另一個線程需要3分鐘,這取決於要處理的文件數量。 – ColinMc

+0

@ user1750090我明白了。喚醒主線程的作用是什麼?要找到更多的工作要做,並開始一個新的線程?你有沒有像一個線程正在尋找工作要做,而多個線程正在處理該工作? – maasg

+0

喚醒主線程的作用是在完成一個線程時創建更多的線程。基本上它會爲每個公司創建一個線程來處理文件,當一個公司完成後,它將返回到主線程並創建另一個公司線程來處理。不,我沒有一個線程在多線程處理工作時正在尋找工作。我擁有的唯一線程是產生公司線程和公司線程進行文件處理的主線程。 – ColinMc