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 服务日志或客户端日志中也没有记录错误。我的假设是我等待并通知错误,或者我错过了一些信息。

可运行线程代码:

在运行方法结束时

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

我之所以进行等待和通知过程是因为我不希望主类运行,除非需要创建另一个线程。

主类的目的是产生线程。该类有一个无限循环来永远运行创建和完成线程。

无限循环的目的是不断更新公司列表。

4

1 回答 1

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 注释),即在执行(消费)任务的同时产生新工作,那么这种方法应该足以在多个线程之间并行处理工作以一种简单的方式。

如果您有额外的要求,为什么要在处理工作时交错查找新工作,您应该在问题中明确说明。

于 2012-11-22T21:03:34.690 回答