并行java应用程序没有接收CPU来完成任务

时间:2015-09-09 13:46:52

标签: java multithreading

我有一个并行运行的java应用程序,它消耗大量日志文件并应用一些自定义逻辑。使用“即发即弃”方法在单独的线程中处理每个日志行。

然而,有时java进程只是停止处理,我的意思是java应用程序没有被分配CPU来执行进程,即使应用程序仍然没有完成使用该文件。

运行 top 考虑到我拥有16个核心,我的平均负载相当低:

enter image description here

运行 vmstat 我可以看到非用户进程既没有运行内核进程,也没有运行99%

enter image description here

iostat 的输出显示我没有正在运行的待处理IO任务:

enter image description here

我还没有发现线程转储的任何死锁或饥饿。大多数线程都是WAITING或RUNNABLE。

我错过了什么?我迷路了,而且我不知道在哪里进一步调查。

= UPDATE =

这是启动并行执行的部分,此后有数千行代码应用修改包括。 elasticsearch,akka等

所以我真的不知道可能会导致任何麻烦的相关代码是什么。

BlockingQueue<Runnable> workQueue =  new ArrayBlockingQueue<Runnable>(100);
ExecutorService executorService =  new MetricsThreadPoolExecutor(numThreadCore, numThreadCore, idleTime, TimeUnit.SECONDS, workQueue, new ThreadPoolExecutor.AbortPolicy(), "process.concurrent", metrics);

FileInputStream fileStream = new FileInputStream(file);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new GZIPInputStream(fileStream));
String strRow = bufferedReader.readLine();

while (strRow != null) {
    final Row row = new Row(strRow);

    try {
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                if (!StringUtil.isBlank(row.getLine())) {
                    processor.process(row);
                }
            }
        });

        strRow = bufferedReader.readLine();

    } catch (RejectedExecutionException ree) {
        try {
            logger.warn(ree.getMessage());
            Thread.sleep(50L);
        } catch (InterruptedException ie) {
            logger.warn("Wait interrupted", ie);
        }
    }

1 个答案:

答案 0 :(得分:1)

  

然而,有时java进程只是停止处理,我的意思是java应用程序没有被分配CPU来执行进程,即使应用程序仍然没有完成使用该文件。

不要在CPU / vmstat / iostat级别考虑这个问题。这只是混淆了问题的调试。您应该仅考虑线程,并相信操作系统可以适当地安排它们。

我认为没有理由在提交所有行进行处理后主线程不能完成。顺便说一句,您可能只想阻止生成器,而不是像您正在做的那样重新生成旋转/睡眠循环中的行。请参阅:RejectedExecutionException free threads but full queue

如果应用程序未完成,则处理行时可能会挂起其中一个工作线程,或者MetricsThreadPoolExecutor尚未关闭。我怀疑后者。生成器线程退出while (strRow != null) {循环后应调用executorService.shutdown()。否则,线程将等待添加更多行。

您可以在应用程序上执行线程转储,以查看它是否卡在了工作程序中。您可以在生产者线程完成时添加日志记录,这可以让您知道它是否完成了它的工作。两者都可能有助于找出问题所在。