103.【Java Microbenchmark Harness】(二)

简介: 103.【Java Microbenchmark Harness】

3.@State (状态)【类】

源码

@State(Scope.Thread) //各个线程独自占有一个对象
@State(Scope.Benchmark)  //整个测试总共用这一个对象
package org.openjdk.jmh.samples;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
 *   @State(Scope.XXXX) 描述了这个类对象的作用域
 *   测试共享与独享的区别
 */
@Warmup(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS)  //预热次数和时间
@Measurement(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //测试次数和时间
public class JMHSample_03_States {
    // 所有测试线程各用各的 (独享)
    @State(Scope.Thread) //各个线程独自占有一个对象
    public static class ThreadState {  //在我们执行Benchmark的时候,他会生成一个ThreadState对象。可以被Benchmark直接使用的,也就是入参。
        volatile double x = Math.PI;
    }
    // 根据main方法,会启动4个线程去一起执行
    @Benchmark
    public void measureUnshared(ThreadState state) {  //每一个线程的入参都是不同的对象
        state.x++;
    }
    // 所有测试共享一个实列,用于测试有状态实列在多线程共享下的性能
    // 一般用来测试多线程竞争下的性能
    @State(Scope.Benchmark)  //整个测试总共用这一个对象
    public static class BenchmarkState {
        volatile double x = Math.PI;
    }
    @Benchmark
    public void measureShared(BenchmarkState state) {  //这个依然启动4个进程,但是入参都是同一个实列,竞争非常激烈
        state.x++;
    }
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_03_States.class.getSimpleName())
                .threads(4)   //在执行Benchmark的时候会启动4个线程
                .forks(1)
                .build();
        new Runner(opt).run();
    }
}

4.DefaultState (默认状态)【类】

源码

@State(Scope.Thread)  //放在整体类上
package org.openjdk.jmh.samples;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)  //我们标记这个类会成为一个对象由JMH进行管理。多个线程会创建多个下面类对象
@Warmup(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS)  //预热次数和时间
@Measurement(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //测试次数和时间
public class JMHSample_04_DefaultState {
    double x = Math.PI;
    // 我们使用默认静态类的主要目的是:  我们不用特地的去写一个静态内部类去声明一个入参。如果没有上面的注解那么我们就需要声明一个静态内部类
    @Benchmark
    public void measure() {
        x++;
    }
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_04_DefaultState.class.getSimpleName())
                .forks(1)
                .build();
        new Runner(opt).run();
    }
}

5.@Setup和@TearDown (初始化和销毁)【方法】

启动之前准备工作

// 启动Benchmark之前的准备工作
    @Setup // 必须在@State下的类中才能使用,实际上也算是@state管理对象的生命周期一部分

结束之后检查工作

// Benchmark结束之后的检查工作
    @TearDown  //必须在@State下的类中才能使用

源码

package org.openjdk.jmh.samples;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
/**
 *   控制state 对象中的方法在什么时候执行
 *
 *   @Setup state中的方法如何被执行
 *   @TearDown state中的方法如何执行
 *   level.Trial 默认的执行策略,整个基准测试执行一次
 */
@State(Scope.Thread)  //生命默认静态类,我们可以不用进行手动传入参数
@Warmup(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS)  //预热次数和时间
@Measurement(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //测试次数和时间
public class JMHSample_05_StateFixtures {
    double x;
    // 启动Benchmark之前的准备工作
    @Setup // 必须在@State下的类中才能使用,实际上也算是@state管理对象的生命周期一部分
    public void prepare() {
        x = Math.PI;
        System.out.println("--------------1");
    }
    // Benchmark结束之后的检查工作
    @TearDown  //必须在@State下的类中才能使用
    public void check() {
        System.out.println("--------------2");
        // 这里使用了断言
        assert x > Math.PI : "Nothing changed?";
    }
    @Benchmark
    public void measureRight() {  //正确代码,正常执行
        x++;
    }
    @Benchmark
    public void measureWrong() {  // 这里是错误代码实列,会在Benchmark执行完毕后报错
        double x = 0;
        x++;
    }
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_05_StateFixtures.class.getSimpleName())
                .forks(1)
                .jvmArgs("-ea")  //开启断言检测: assertion在一般情况下是关闭的,通过 java -ea 可以打开改功能,关闭为 -da
                .build();
        new Runner(opt).run();
    }
}

6.FixtureLevel (初始化和销毁等级)【方法】

源码

@Setup(Level.Trial)  // 与TearDown同理.启动之前会执行一次
   @TearDown(Level.Trial)  // 整个完整的基准测试之后才会执行一次
   @TearDown(Level.Iteration)  // 每轮循环完成之后才会执行一次
   @TearDown(Level.Invocation)  // 每次方法被调用都会执行一次
package org.openjdk.jmh.samples;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)  //可以免除静态内部类
@Warmup(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS)  //预热次数和时间
@Measurement(iterations = 3,time = 1,timeUnit = TimeUnit.SECONDS) //测试次数和时间
public class JMHSample_06_FixtureLevel {
    double x;
//    @Setup(Level.Trial)  // 与TearDown同理.启动之前会执行一次
//    @TearDown(Level.Trial)  // 整个完整的基准测试之后才会执行一次
//    @TearDown(Level.Iteration)  // 每轮循环完成之后才会执行一次
//     @TearDown(Level.Invocation)  // 每次方法被调用都会执行一次
    @TearDown(Level.Iteration)  // 每次方法被调用都会执行一次
    public void check() {
        System.out.println("----------1");
        assert x > Math.PI : "Nothing changed?";
    }
    @Benchmark
    public void measureRight() {
        x++;
    }
    @Benchmark
    public void measureWrong() {
        double x = 0;
        x++;
    }
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_06_FixtureLevel.class.getSimpleName())
                .forks(1)
                .jvmArgs("-ea")
                .shouldFailOnError(false) //  默认是false,即使assert错误也不会让整个测试失败
                .build();
        new Runner(opt).run();
    }
}

相关文章
|
JSON 数据可视化 Java
103.【Java Microbenchmark Harness】(六)
103.【Java Microbenchmark Harness】
68 0
103.【Java Microbenchmark Harness】(六)
|
Java
103.【Java Microbenchmark Harness】(三)
103.【Java Microbenchmark Harness】
60 0
103.【Java Microbenchmark Harness】(三)
|
Java
103.【Java Microbenchmark Harness】(五)
103.【Java Microbenchmark Harness】
139 0
|
Java 编译器 BI
103.【Java Microbenchmark Harness】(四)
103.【Java Microbenchmark Harness】
84 0
|
Java 测试技术
103.【Java Microbenchmark Harness】(一)
103.【Java Microbenchmark Harness】
85 0
|
Java 测试技术
在java中使用JMH(Java Microbenchmark Harness)做性能测试
在java中使用JMH(Java Microbenchmark Harness)做性能测试
|
2天前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
33 14
|
5天前
|
安全 Java 程序员
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
34 13
|
6天前
|
安全 Java 开发者
【JAVA】封装多线程原理
Java 中的多线程封装旨在简化使用、提高安全性和增强可维护性。通过抽象和隐藏底层细节,提供简洁接口。常见封装方式包括基于 Runnable 和 Callable 接口的任务封装,以及线程池的封装。Runnable 适用于无返回值任务,Callable 支持有返回值任务。线程池(如 ExecutorService)则用于管理和复用线程,减少性能开销。示例代码展示了如何实现这些封装,使多线程编程更加高效和安全。
|
1月前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
109 17

热门文章

最新文章