Java线程:CPU利用率过高

时间:2016-04-18 11:00:50

标签: java multithreading cpu-usage

我使用的服务会从Kafka读取邮件并将其推送到Cassandra

我使用的是线程架构。

有人说,k threads正在消费Kafka主题。这些写入队列,声明为:

public static BlockingQueue<>

现在有很多线程,比如n,写入Cassandra。以下是执行此操作的代码:

public void run(){
    LOGGER.log(Level.INFO, "Thread Created: " +Thread.currentThread().getName());
    while (!Thread.currentThread().isInterrupted()) {
        Thread.yield();
        if (!content.isEmpty()) {
            try {
                JSONObject msg = content.remove();
                // JSON
                for(String tableName : tableList){
                    CassandraConnector.getSession().execute(createQuery(tableName, msg));
                }
            } catch (Exception e) {

            }
        }
    }
}

content是用于读写操作的BlockingQueue。

我在线程实现中扩展Thread类,并且有一定数量的线程继续执行,除非被中断。

问题是,这是使用太多的CPU。这是top命令的第一行:

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
46232 vishran+  20   0 3010804 188052  14280 S 137.8  3.3   5663:24 java

以下是此过程的一个主题上strace的输出:

strace -t -p 46322
Process 46322 attached
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
15:18:47 sched_yield()                  = 0
....and so on

为什么我使用Thread.yield(),是因为this

如果您需要任何其他信息进行调试,请告知我们。

现在的问题是,如何最大限度地降低CPU利用率?

3 个答案:

答案 0 :(得分:7)

BlockingQueue的全部目的是它在空时阻塞。因此,消费者线程(填充到Cassandra中的线程)不必手动检查它们是否为空。您可以只调用take(),如果队列为空,则调用将被阻塞,除非它被中断或者有可用的元素。

当一个线程被阻塞时,调度程序可以在其位置安排一些其他线程,这样可以避免调用yield()等等。请记住,只有当优先级大于或等于正在产生的线程的线程可以运行时,yield()才会让位给另一个线程。

public void run(){
    LOGGER.log(Level.INFO, "Thread Created: " +Thread.currentThread().getName());
    try {
            JSONObject msg = content.take();
            // JSON
            for(String tableName : tableList){
                CassandraConnector.getSession().execute(createQuery(tableName, msg));
            }
     } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
     }
}

答案 1 :(得分:3)

从代码的外观来看,您的消费者线程似乎总是在检查可用的内容。因此,你的线程总是在运行而且从不谜语(等待有人通知它们),因此你的CPU总是做一些事情,即使它总是让线程成为当前线程。

while (!Thread.currentThread().isInterrupted()) { Thread.yield(); if (!content.isEmpty()) {

你显然已经想要解决生产者 - 消费者问题,我们很多人都在这个问题上面对我们的编程职业。

您目前正在做的是让消费者主动不断检查是否有消费品。

解决问题的最简单,最简单的CPU密集方式是:

  1. 让制作人告知消费者它已经制作了一些东西。
  2. 查看this example,因为它包含最简单的方法。您可能需要重新访问Java Concurrency in Practice以获得更深刻的帮助。

答案 2 :(得分:0)

正如其他答案中所述,您正在忙着等待而不是使用content BlockingQueue的核心功能:等待下一个条目并将其从队列中删除。这是使用take()方法完成的:

while (!Thread.currentThread().isInterrupted()) {
    try {
        JSONObject msg = content.take();
        for(String tableName : tableList){
            CassandraConnector.getSession().execute(createQuery(tableName, msg));
        }
    } catch (Exception e) {

    }
}