构建一个简单的Java框架来测量并发执行任务的时间
文章目录
- 一、完整代码
- 二、代码解释
- 1、方法签名
- 2、初始化CountDownLatch
- 3、提交任务到执行器
- 4、任务线程的逻辑
- 5、主线程的逻辑
- 详细解释
- 总结
以下代码实现了一个简单的框架,用于测量并发执行任务的时间。它使用了Executor来执行任务,并通过CountDownLatch来协调多个线程的执行。
假设我们使用一个简单的任务(如打印线程名称和任务编号),并运行这个方法。
一、完整代码
import java.util.concurrent.*;// Simple framework for timing concurrent execution
public static long time(Executor executor, int concurrency, Runnable action) throws InterruptedException {// 创建一个计数器,用于确保所有任务线程都已准备好CountDownLatch ready = new CountDownLatch(concurrency);// 创建一个计数器,用于通知所有任务线程开始执行CountDownLatch start = new CountDownLatch(1);// 创建一个计数器,用于确保所有任务线程都已完成CountDownLatch done = new CountDownLatch(concurrency);// 提交 concurrency 个任务到执行器for (int i = 0; i < concurrency; i++) {executor.execute(() -> {// 每个任务线程在开始执行前调用 countDown,表示已准备好ready.countDown(); // Tell timer we're readytry {// 每个任务线程等待 start 的计数器变为 0,即等待主线程通知开始执行start.await(); // Wait till peers are ready// 执行传入的 Runnable 任务action.run();} catch (InterruptedException e) {// 如果捕获到 InterruptedException,重新设置当前线程的中断状态Thread.currentThread().interrupt();} finally {// 每个任务线程执行完毕后,调用 countDown,表示已完成done.countDown(); // Tell timer we're done}});}// 主线程等待所有任务线程都准备好ready.await(); // Wait for all workers to be ready// 记录开始时间long startNanos = System.nanoTime();// 主线程通知所有任务线程开始执行start.countDown(); // And they're off!// 主线程等待所有任务线程都完成done.await(); // Wait for all workers to finish// 计算并返回任务执行的总时间(纳秒)return System.nanoTime() - startNanos;
}
为了更直观地理解这段代码的运行逻辑和输出效果,我们可以补充具体的输入参数,并展示完整的运行过程和最终输出。假设我们使用一个简单的任务(如打印线程名称和任务编号),并运行这个方法。
import java.util.concurrent.*;public class ConcurrentTimingFramework {// Simple framework for timing concurrent executionpublic static long time(Executor executor, int concurrency, Runnable action) throws InterruptedException {// 创建一个计数器,用于确保所有任务线程都已准备好CountDownLatch ready = new CountDownLatch(concurrency);// 创建一个计数器,用于通知所有任务线程开始执行CountDownLatch start = new CountDownLatch(1);// 创建一个计数器,用于确保所有任务线程都已完成CountDownLatch done = new CountDownLatch(concurrency);// 提交 concurrency 个任务到执行器for (int i = 0; i < concurrency; i++) {executor.execute(() -> {// 每个任务线程在开始执行前调用 countDown,表示已准备好ready.countDown(); // Tell timer we're readytry {// 每个任务线程等待 start 的计数器变为 0,即等待主线程通知开始执行start.await(); // Wait till peers are ready// 执行传入的 Runnable 任务action.run();} catch (InterruptedException e) {// 如果捕获到 InterruptedException,重新设置当前线程的中断状态Thread.currentThread().interrupt();} finally {// 每个任务线程执行完毕后,调用 countDown,表示已完成done.countDown(); // Tell timer we're done}});}// 主线程等待所有任务线程都准备好ready.await(); // Wait for all workers to be ready// 记录开始时间long startNanos = System.nanoTime();// 主线程通知所有任务线程开始执行start.countDown(); // And they're off!// 主线程等待所有任务线程都完成done.await(); // Wait for all workers to finish// 计算并返回任务执行的总时间(纳秒)return System.nanoTime() - startNanos;}public static void main(String[] args) throws InterruptedException {// 创建一个线程池,线程池大小为 4ExecutorService executor = Executors.newFixedThreadPool(4);// 定义并发级别int concurrency = 4;// 定义要执行的任务Runnable action = () -> {System.out.println("Task executed by " + Thread.currentThread().getName());};// 调用 time 方法,测量并发执行的时间long duration = time(executor, concurrency, action);// 打印执行时间System.out.println("Total execution time: " + duration + " nanoseconds");// 关闭线程池executor.shutdown();}
}
假设运行环境中有足够的线程资源,输出可能如下:
Task executed by pool-1-thread-1
Task executed by pool-1-thread-2
Task executed by pool-1-thread-3
Task executed by pool-1-thread-4
Total execution time: 1234567 nanoseconds
二、代码解释
1、方法签名
public static long time(Executor executor, int concurrency, Runnable action) throws InterruptedException {
参数:
- Executor executor:一个执行器,用于执行任务。
- int concurrency:并发级别,即同时运行的任务数量。
- Runnable action:要执行的任务。
- 返回值:long,表示任务执行的总时间(纳秒)。
- 异常:throws InterruptedException,表示方法可能会抛出InterruptedException。
2、初始化CountDownLatch
CountDownLatch ready = new CountDownLatch(concurrency);
CountDownLatch start = new CountDownLatch(1);
CountDownLatch done = new CountDownLatch(concurrency);
- ready:用于确保所有任务线程都已准备好。
- start:用于通知所有任务线程开始执行。
- done:用于确保所有任务线程都已完成。
3、提交任务到执行器
for (int i = 0; i < concurrency; i++) {executor.execute(() -> {
- 提交concurrency个任务到executor。
- 每个任务是一个Runnable,使用Lambda表达式实现。
4、任务线程的逻辑
ready.countDown(); // Tell timer we're ready
try {start.await(); // Wait till peers are readyaction.run();
} catch (InterruptedException e) {Thread.currentThread().interrupt();
} finally {done.countDown(); // Tell timer we're done
}
- ready.countDown():每个任务线程在开始执行前调用countDown,表示已准备好。
- start.await():任务线程等待start的计数器变为0,即等待主线程通知开始执行。
- action.run():执行传入的Runnable任务。
- catch (InterruptedException e):捕获InterruptedException,并重新设置当前线程的中断状态。
- done.countDown():任务线程执行完毕后,调用countDown,表示已完成。
5、主线程的逻辑
ready.await(); // Wait for all workers to be ready
long startNanos = System.nanoTime();
start.countDown(); // And they're off!
done.await(); // Wait for all workers to finish
return System.nanoTime() - startNanos;
- ready.await():主线程等待所有任务线程都准备好。
- startNanos = System.nanoTime():记录开始时间。
- start.countDown():主线程通知所有任务线程开始执行。
- done.await():主线程等待所有任务线程都完成。
- return System.nanoTime() - startNanos:计算并返回任务执行的总时间(纳秒)。
详细解释
- 任务线程的准备阶段:
每个任务线程调用ready.countDown(),表示已准备好。
主线程调用ready.await(),等待所有任务线程准备好。 - 任务线程的执行阶段:
主线程调用start.countDown(),通知所有任务线程开始执行。
每个任务线程调用start.await(),等待主线程的通知。
任务线程执行action.run(),打印当前线程的名称。 - 任务线程的完成阶段:
每个任务线程调用done.countDown(),表示已完成。
主线程调用done.await(),等待所有任务线程完成。 - 计算执行时间:
主线程记录任务开始时间和结束时间,计算总时间并返回。
总结
通过这个示例,我们可以看到time方法如何使用CountDownLatch来协调多个任务线程的执行,并测量任务的总执行时间。希望这个详细的解释和示例能帮助你更好地理解代码的运行逻辑和输出效果!