衡量消费者/生产者的工作时间

时间:2017-04-27 05:57:36

标签: java time concurrency

生产者和消费者的当前配置:

ExecutorService consumerExecutor = createExecutor(...);
ExecutorService producerExecutor = createExecutor(...);

try {
    List<Callable<Integer>> callablesForConsumer = createListOfCallablesForConsumer(...);
    List<Callable<Integer>> callablesForProducer = createListOfCallablesForProducer(...);
    ....
    ....
    // submitting tasks to executors and combine them into one list of futures
    ....
    ....
    for (Future<Integer> future : futures) {
        intCount += future.get();
    }
    ....
    ....
    // some business logic
    ....
    ....
} finally {
    consumerExecutor.shutdown();
    producerExecutor.shutdown();
}

如何衡量和记录消费者和生产者单独花费的总时间

因此我需要得到这样的结果:producerTotalTime=... ms, consumerTotalTime=... ms

我是否应该覆盖一些执行者服务方法,对此有什么想法?

1 个答案:

答案 0 :(得分:2)

您可以覆盖ThreadPoolExecutor的两种方法:

beforeExecute(Thread t, Runnable r)afterExecute(Runnable r, Throwable t)都采用runnable,因此请使用runnable计算其执行时间(在例如。ConcurrentHashMap<Runable, Long>中映射runnable)

然后在beforeExecute中,将RunnableSystem.currentTimeMillis()放入地图。

afterExecute

,按startTime从地图中取出Runnable,并从地图中删除此Runnable。然后使用startTime计算long taskExecutionTime = System.currentTimeMillis() - startTime 然后使用AtomicLong汇总每个runnable中的所有taskExecutionTime

使用ConcurrentHashMap您只需要添加新的Runnables,因为添加相同的Runnable两次或更多次将覆盖前一个。如果您想多次添加相同的runnable,请使用一些MultiMap实现(例如来自commons-collection或guava)。这个MultiMap需要是Concurrent implementation(线程安全)。

另一种选择是使用一些ThreadLocal变量而不是ConcurrentHashMap,因为每个Runnable都在自己的(执行的那一刻)执行Thread。在执行之前将startTime添加到threadLocal,在afterExecute中获取并计算taskExecutionTime。

第二种情况下的实施可能如下:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class TimedExecutor extends ThreadPoolExecutor {
    private ThreadLocal<Long> startTime = new ThreadLocal<>();
    private AtomicLong totalExecutionTime = new AtomicLong(0);

    public TimedExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
            BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        startTime.set(System.currentTimeMillis());
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        long taskExecutionTime = System.currentTimeMillis() - startTime.get();
        totalExecutionTime.addAndGet(taskExecutionTime);
    }

    public long totalExecutionTime() {
        return totalExecutionTime.get();
    }

    public static TimedExecutor newFixedThreadPool(int noOfThreads) {
        int corePoolSize = noOfThreads;
        int maximumPoolSize = noOfThreads;
        return new TimedExecutor(corePoolSize, maximumPoolSize, 0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
    }
}

如果您想测量特定ExecutorService运行和完成某些特定任务所需的时间,那么这可能会给您一个提示:

import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class MeasureExecutorTime {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); // any executor - your choice
        LinkedList<Runnable> runnables = new LinkedList<>(); // place your Runnables here, to minimize influence of initialization.

        long startTime = System.currentTimeMillis();
        for (Runnable command : runnables) {
            executorService.execute(command);
        }
        executorService.shutdownNow();
        // next line will block till all tasks finishes
        executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);

        long totalExecutionTime = System.currentTimeMillis() - startTime;
    }
}