构建一个简单的Java框架来测量并发执行任务的时间

文章目录

以下代码实现了一个简单的框架,用于测量并发执行任务的时间。它使用了Executor来执行任务,并通过CountDownLatch来协调多个线程的执行。

假设我们使用一个简单的任务(如打印线程名称和任务编号),并运行这个方法。

一、完整代码

java 复制代码
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 ready
            try {
                // 每个任务线程等待 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;
}

为了更直观地理解这段代码的运行逻辑和输出效果,我们可以补充具体的输入参数,并展示完整的运行过程和最终输出。假设我们使用一个简单的任务(如打印线程名称和任务编号),并运行这个方法。

java 复制代码
import java.util.concurrent.*;

public class ConcurrentTimingFramework {

    // 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 ready
                try {
                    // 每个任务线程等待 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 {
        // 创建一个线程池,线程池大小为 4
        ExecutorService 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();
    }
}

假设运行环境中有足够的线程资源,输出可能如下:

java 复制代码
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、方法签名

java 复制代码
public static long time(Executor executor, int concurrency, Runnable action) throws InterruptedException {

参数:

  • Executor executor:一个执行器,用于执行任务。
  • int concurrency:并发级别,即同时运行的任务数量。
  • Runnable action:要执行的任务。
  • 返回值:long,表示任务执行的总时间(纳秒)。
  • 异常:throws InterruptedException,表示方法可能会抛出InterruptedException。

2、初始化CountDownLatch

java 复制代码
CountDownLatch ready = new CountDownLatch(concurrency);
CountDownLatch start = new CountDownLatch(1);
CountDownLatch done = new CountDownLatch(concurrency);
  • ready:用于确保所有任务线程都已准备好。
  • start:用于通知所有任务线程开始执行。
  • done:用于确保所有任务线程都已完成。

3、提交任务到执行器

java 复制代码
for (int i = 0; i < concurrency; i++) {
    executor.execute(() -> {
  • 提交concurrency个任务到executor。
  • 每个任务是一个Runnable,使用Lambda表达式实现。

4、任务线程的逻辑

java 复制代码
ready.countDown(); // Tell timer we're ready
try {
    start.await(); // Wait till peers are ready
    action.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、主线程的逻辑

java 复制代码
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来协调多个任务线程的执行,并测量任务的总执行时间。希望这个详细的解释和示例能帮助你更好地理解代码的运行逻辑和输出效果!

相关推荐
captain37624 分钟前
MyBatis操作数据库(入门2)
java·数据库·spring boot·后端·spring·mybatis
2601_970703831 小时前
工业除湿机租赁:把一份租金合同拆开看
大数据·数据结构·算法·数据库架构·推荐算法
心中有你02141 小时前
Java实现Dijkstra最短路径算法(邻接表 + 优先队列)
java·数据库·算法
步行cgn1 小时前
Spring MVC + Thymeleaf 模板解析失败:从 500 错误到页面正常显示
java·spring·mvc
ZhengEnCi2 小时前
同样的模型,为什么本地和云 API 差别那么大:量化精度、聊天模板与采样参数的三大元凶
人工智能·算法·llm
lgcgkCQ2 小时前
【AI 转型实战 1】SpringAI 入门:搭建基础大模型对话能力
java·ai·agent·rag·spring ai·mcp·langchain4j
Wang's Blog2 小时前
Java 项目实战:交友项目 - 用户体系集成总结
java·开发语言·交友
学到老活到老2 小时前
第 24 集:配置文件写了 80,Spring Boot 为什么读到 90?
java·后端·spring
Flynn Liang2 小时前
RAG 答非所问/幻觉怎么破?Spring AI QuestionAnswerAdvisor 召回优化实战(TopK/重排/混合检索)
人工智能·算法·spring·rag·幻觉·springai
liminla!2 小时前
SQL 从入门到进阶:语法速查与实战练习(完整优化版)
数据库·sql·算法