java - 为什么我的 native JNI 代码是顺序运行而不是并发运行?

标签 java c java-native-interface jmh

原始问题(带有完整代码)

(我保留了原始的完整代码,因为下面的答案与此完整代码相关。)

我目前正在研究有关节能软件工程的硕士论文项目,我想(粗略地)监控不同 Java 方法的能耗行为。

所需行为的简短描述:

我有一组 JMH 基准测试,我想使用 Intel Power Gadget API 对其进行分析。所需的行为应该如下所示:

  • 在每个方法进行基准测试之前,应创建并启动一个新线程,该线程将执行分析部分。
  • 在“主”线程的基准测试期间,分析器线程应读取样本,直到执行 JMH 拆卸方法。

我的问题:

代码按顺序执行,而不是所需的并发执行。 “分析阶段”应在 JMH 设置中开始,在 JMH 拆卸方法中结束。

我的代码:

该代码仍处于实验阶段且困惑。对此感到抱歉。我仍然保留所有调试打印语句用于记录目的。

BenchmarkProgram.java:

package Profiling;

public class BenchmarkProgram {

    public static void main(String[] args) throws Exception{
        org.openjdk.jmh.Main.main(args);
    }
}

PowerGadgetProfiler.java:

package Profiling;


import BenchmarkContainers.BenchmarkContainer;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;

public class PowerGadgetProfiler {

    static{
        System.loadLibrary("PowerGadgetProfiler");
        System.out.println("THREAD " + Thread.currentThread().getId() +  " LIBRARY LOADED SUCCESSFULLY");
    }

    public static int profileId = 0;
    static int methodCounter = 0;

    private static final String folderName = buildFolderName();

    public static final Object profilerLock = new Object();

    public static volatile boolean running = false;

    private static final PowerGadgetProfiler instance = new PowerGadgetProfiler();

    private static String[] getBenchmarkMethodsInOrder(){
        ArrayList<String> methodNames = new ArrayList<>();
        Method[] methods = BenchmarkContainer.class.getMethods();
        for (Method method : methods) {
            String name = method.toString();
            if(name.contains("BenchmarkContainer")
            && !name.contains("initializeProfilerThread")
            && !name.contains("stopProfiling")){
                methodNames.add(method.getName());
            }
        }
        String[] methodArray = methodNames.toArray(new String[0]);
        Arrays.sort(methodArray);
        System.out.println("THREAD " + Thread.currentThread().getId() + " METHODS: " + Arrays.toString(methodArray));
        return methodArray;
    }

    private static String buildFolderName(){
        LocalDateTime timeStamp = LocalDateTime.now();
        String result = "/Users/timerdar/BM-";          // change when on other machine
        result += Integer.toString(timeStamp.getYear());
        result += Integer.toString(timeStamp.getMonthValue());
        result += Integer.toString(timeStamp.getDayOfMonth());
        result += Integer.toString(timeStamp.getHour());
        result += Integer.toString(timeStamp.getMinute());
        return result;
    }

    private static String buildFileName(){
        return folderName + "/" + benchmarkMethods[methodCounter] + profileId + ".csv";
    }

    private static final String[] benchmarkMethods = getBenchmarkMethodsInOrder();

    private native void startProfiling(String fileName);

    private native void readSample();

    private native void stopProfiling();

    public static void startProfiling(){
        System.out.println("THREAD " + Thread.currentThread().getId() + " ENTERED START PROFILING");
        synchronized(profilerLock) {
            System.out.println("THREAD " + Thread.currentThread().getId() + " RELEASES PROFILER LOCK");
            profilerLock.notify();
        }
        final String fileName = buildFileName();
        instance.startProfiling(fileName);
        System.out.println("THREAD " + Thread.currentThread().getId() + " CALLED PROFILE EXECUTION");
        profileId++;
        while(running){
            getSample();
        }
        endProfiling();
    }

    private static void getSample(){
        instance.readSample();
    }

    private static void endProfiling(){
        System.out.println("THREAD " + Thread.currentThread().getId() + " ENTERED endProfiling()");
        instance.stopProfiling();
        System.out.println("JAVA THREAD " + Thread.currentThread().getId() + " CALLED NATIVE stopProfiling()");
        methodCounter++;
    }
}

BenchmarkContainer.java:

这只是我拥有的所有基准测试的一小部分。我减少了基准测试的数量,以减少创建概念验证时的开销。

package BenchmarkContainers;

import Profiling.PowerGadgetProfiler;
import Profiling.ProfilerThread;
import org.openjdk.jmh.annotations.*;

import java.util.concurrent.TimeUnit;

@State(Scope.Benchmark)
public class BenchmarkContainer {

    //@Param({"5", "30",  "210", "1470"})
    @Param({"1", "2"})
    public int upperBound;

    @Setup(Level.Trial)
    public void initializeProfilerThread() {
        System.out.println("THREAD " + Thread.currentThread().getId() + " ENTERED initializeProfilerThread()");
        ProfilerThread profilerThread = new ProfilerThread();
        profilerThread.start();
        synchronized (PowerGadgetProfiler.profilerLock){
            try {
                System.out.println("THREAD " + Thread.currentThread().getId() + " WAITS FOR PROFILER LOCK");
                PowerGadgetProfiler.profilerLock.wait();
                PowerGadgetProfiler.running = true;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @TearDown(Level.Trial)
    public void stopProfiling(){
        System.out.println("THREAD " + Thread.currentThread().getId() + " ENTERED TEARDOWN PROCEDURE");
        synchronized (PowerGadgetProfiler.profilerLock){
            PowerGadgetProfiler.running = false;
        }
    }

    @Benchmark
    @Fork(value = 1, warmups = 1)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    @BenchmarkMode(Mode.AverageTime)
    public void init(){
        {

        }
    }

    @Benchmark
    @Fork(value = 1, warmups = 1)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    @BenchmarkMode(Mode.AverageTime)
    public int geoSum(){
        int sum = 0;
        for(int i = 0; i <= upperBound; i++){
            sum += i;
        }
        return sum;
    }
}

ProfilerThread.java:

package Profiling;

public class ProfilerThread extends Thread{

    @Override
    public void run() {
        System.out.println("STARTING PROFILING IN PROFILER THREAD");
        PowerGadgetProfiler.startProfiling();
    }
}

Profiling_PowerGadgetProfiler.c:

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <IntelPowerGadget/EnergyLib.h>
#include <pthread.h>

#include "Profiling_PowerGadgetProfiler.h"

JNIEXPORT void JNICALL Java_Profiling_PowerGadgetProfiler_startProfiling
  (JNIEnv *env, jobject thisObject, jstring fileName)
  {
      uint64_t tid;
      pthread_threadid_np(NULL, &tid);
      printf("THREAD %llu CALLED NATIVE startProfiling()\n", tid);


      IntelEnergyLibInitialize();

      printf("NATIVE PROFILER INITIALIZED\n");
      char fileNameAsString[255];

      const char *fileNameAsConstString = (*env)->GetStringUTFChars(env, fileName, 0);

      strcpy(fileNameAsString, fileNameAsConstString);

      printf("RESULTING FILE NAME: %s\n", fileNameAsString);
      printf("STARTING PROFILING IN NATIVE CODE\n");

      StartLog(fileNameAsString);

  }


JNIEXPORT void JNICALL Java_Profiling_PowerGadgetProfiler_readSample
  (JNIEnv *env , jobject thisObject)
{
    ReadSample();
}

JNIEXPORT void JNICALL Java_Profiling_PowerGadgetProfiler_stopProfiling
 (JNIEnv* env, jobject thisObject)
{
    uint64_t tid;
    pthread_threadid_np(NULL, &tid);
    printf("THREAD %llu CALLED NATIVE stopProfiling()\n", tid);
    printf("ENDING PROFILING IN NATIVE CODE AND WRITE TO FILE\n");
    StopLog();
}

控制台输出:

请不要担心 JMH 和我的输出的混合。这对我来说并不重要。

# JMH version: 1.32
# VM version: JDK 14.0.1, OpenJDK 64-Bit Server VM, 14.0.1+7
# VM invoker: /Users/timerdar/Library/Java/JavaVirtualMachines/openjdk-14.0.1/Contents/Home/bin/java
# VM options: -Djava.library.path=/Users/timerdar/IdeaProjects/microbenchmark_test/src/main/java/Profiling -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=62464:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint
# Warmup: 5 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: BenchmarkContainers.BenchmarkContainer.geoSum
# Parameters: (upperBound = 1)

# Run progress: 0,00% complete, ETA 00:13:20
# Warmup Fork: 1 of 1
# Warmup Iteration   1: THREAD 16 ENTERED initializeProfilerThread()
STARTING PROFILING IN PROFILER THREAD
THREAD 17 LIBRARY LOADED SUCCESSFULLY
THREAD 17 METHODS: [geoSum, init]
THREAD 16 WAITS FOR PROFILER LOCK
THREAD 17 ENTERED START PROFILING
THREAD 17 RELEASES PROFILER LOCK
THREAD 17 STARTING PROFILING IN PGP WITH PARAM VALUE: 1
THREAD 17 CALLED PROFILE EXECUTION
6,152 ns/op
# Warmup Iteration   2: 6,139 ns/op
# Warmup Iteration   3: 5,688 ns/op
# Warmup Iteration   4: 6,172 ns/op
# Warmup Iteration   5: 6,525 ns/op
Iteration   1: 6,858 ns/op
Iteration   2: 7,265 ns/op
Iteration   3: 7,523 ns/op
Iteration   4: 7,494 ns/op
Iteration   5: THREAD 16 ENTERED TEARDOWN PROCEDURE
7,776 ns/op
THREAD 17 ENTERED endProfiling()
THREAD 204730 CALLED NATIVE startProfiling()
NATIVE PROFILER INITIALIZED
RESULTING FILE NAME: /Users/timerdar/BM-202111301910/geoSum0.csv
STARTING PROFILING IN NATIVE CODE
THREAD 204730 CALLED NATIVE stopProfiling()
ENDING PROFILING IN NATIVE CODE AND WRITE TO FILE

到目前为止我尝试过的:

  • 我将分析的控制流从 native 代码删除到了 Java 代码中。之前,我的 native 代码中有一个静态变量,它指示基准测试的运行状态。调用 ReadSample() 方法,直到此变量交换(C 文件中的其他函数)。

  • 我从 PowerGadgetProfiler startProfilinggetSample 中的函数中删除了 synchronized 关键字>结束分析

感谢您的耐心等待,希望您能帮助我。

重现问题所需的最少代码示例:

我创建了一个最小工作示例,以将问题减少到其主要组件。

代码:

BenchmarkProgram.java

package Profiling;

public class BenchmarkProgram {

    public static void main(String[] args) throws Exception{
        org.openjdk.jmh.Main.main(args);
    }
}

BenchmarkContainer.java

package BenchmarkContainers;

import Profiling.PowerGadgetProfiler;
import Profiling.ProfilerThread;
import org.openjdk.jmh.annotations.*;

@State(Scope.Benchmark)
public class BenchmarkContainer {

    @Param({"1", "2"})
    public int upperBound;

    Thread profilerThread;

    @Setup(Level.Trial)
    public void initializeProfilerThread() {
        profilerThread = new ProfilerThread();
        profilerThread.start();
        PowerGadgetProfiler.running = true;
    }

    @TearDown(Level.Trial)
    public void stopProfiling() {
        PowerGadgetProfiler.running = false;
        try {
            profilerThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    @Benchmark
    @Fork(0)
    public void init() {
        {

        }
    }

    @Benchmark
    @Fork(0)
    public int geoSum() {
        int sum = 0;
        for (int i = 0; i <= upperBound; i++) {
            sum += i;
        }
        return sum;
    }
}

PowerGadgetProfiler.java

package Profiling;

public class PowerGadgetProfiler {

    static {
        System.loadLibrary("PowerGadgetProfiler");
    }

    public static volatile boolean running = false;

    private static native void peep();

    public static void startProfiling() {
        peep();
        System.out.println("MOCK PEEP");
        while (running) {
            getSample();
        }
        endProfiling();
    }

    private static void getSample() {
        // mock sampling
    }

    private static void endProfiling() {
        peep();
        System.out.println("MOCK PEEP");
    }
}

ProfilerThread.java

package Profiling;

public class ProfilerThread extends Thread{

    @Override
    public void run() {
        System.out.println("STARTING PROFILING IN PROFILER THREAD");
        PowerGadgetProfiler.startProfiling();
    }
}

Profiling_PowerGadgetProfiler.c

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <IntelPowerGadget/EnergyLib.h>
#include <pthread.h>

#include "Profiling_PowerGadgetProfiler.h"

JNIEXPORT void JNICALL Java_Profiling_PowerGadgetProfiler_peep
  (JNIEnv *env, jclass thisClass)
  {
    uint64_t tid;
    pthread_threadid_np(NULL, &tid);
    printf("THREAD %llu PEEP\n", tid);
  }

输出:

# JMH version: 1.32
# VM version: JDK 14.0.1, OpenJDK 64-Bit Server VM, 14.0.1+7
# VM invoker: /Users/timerdar/Library/Java/JavaVirtualMachines/openjdk-14.0.1/Contents/Home/bin/java
# VM options: -Djava.library.path=/Users/timerdar/IdeaProjects/microbenchmark_test/src/main/java/Profiling -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=50458:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint
# Warmup: 5 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: BenchmarkContainers.BenchmarkContainer.geoSum
# Parameters: (upperBound = 1)

# Run progress: 0,00% complete, ETA 00:06:40
# Fork: N/A, test runs in the host VM
# *** WARNING: Non-forked runs may silently omit JVM options, mess up profilers, disable compiler hints, etc. ***
# *** WARNING: Use non-forked runs only for debugging purposes, not for actual performance runs. ***
# Warmup Iteration   1: STARTING PROFILING IN PROFILER THREAD
THREAD 14 LIBRARY LOADED SUCCESSFULLY
MOCK PEEP
351509573,446 ops/s
# Warmup Iteration   2: 368618416,430 ops/s
# Warmup Iteration   3: 318780225,551 ops/s
# Warmup Iteration   4: 316404930,396 ops/s
# Warmup Iteration   5: 308587428,671 ops/s
Iteration   1: 307622321,475 ops/s
Iteration   2: 295849314,405 ops/s
Iteration   3: 310904513,944 ops/s
Iteration   4: 298409293,008 ops/s
Iteration   5: MOCK PEEP
293730263,155 ops/s

Result "BenchmarkContainers.BenchmarkContainer.geoSum":
  301303141,197 ±(99.9%) 29045283,861 ops/s [Average]
  (min, avg, max) = (293730263,155, 301303141,197, 310904513,944), stdev = 7542967,981
  CI (99.9%): [272257857,337, 330348425,058] (assumes normal distribution)


# JMH version: 1.32
# VM version: JDK 14.0.1, OpenJDK 64-Bit Server VM, 14.0.1+7
# VM invoker: /Users/timerdar/Library/Java/JavaVirtualMachines/openjdk-14.0.1/Contents/Home/bin/java
# VM options: -Djava.library.path=/Users/timerdar/IdeaProjects/microbenchmark_test/src/main/java/Profiling -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=50458:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint
# Warmup: 5 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: BenchmarkContainers.BenchmarkContainer.geoSum
# Parameters: (upperBound = 2)

# Run progress: 25,00% complete, ETA 00:05:01
# Fork: N/A, test runs in the host VM
# *** WARNING: Non-forked runs may silently omit JVM options, mess up profilers, disable compiler hints, etc. ***
# *** WARNING: Use non-forked runs only for debugging purposes, not for actual performance runs. ***
# Warmup Iteration   1: STARTING PROFILING IN PROFILER THREAD
MOCK PEEP
250420430,065 ops/s
# Warmup Iteration   2: 240512982,879 ops/s
# Warmup Iteration   3: 234267496,579 ops/s
# Warmup Iteration   4: 232677741,065 ops/s
# Warmup Iteration   5: 225373803,499 ops/s
Iteration   1: 225697770,075 ops/s
Iteration   2: 233106892,737 ops/s
Iteration   3: 230332046,340 ops/s
Iteration   4: 220403129,274 ops/s
Iteration   5: MOCK PEEP
222970983,188 ops/s

Result "BenchmarkContainers.BenchmarkContainer.geoSum":
  226502164,323 ±(99.9%) 20064492,546 ops/s [Average]
  (min, avg, max) = (220403129,274, 226502164,323, 233106892,737), stdev = 5210684,997
  CI (99.9%): [206437671,777, 246566656,869] (assumes normal distribution)


# JMH version: 1.32
# VM version: JDK 14.0.1, OpenJDK 64-Bit Server VM, 14.0.1+7
# VM invoker: /Users/timerdar/Library/Java/JavaVirtualMachines/openjdk-14.0.1/Contents/Home/bin/java
# VM options: -Djava.library.path=/Users/timerdar/IdeaProjects/microbenchmark_test/src/main/java/Profiling -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=50458:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint
# Warmup: 5 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: BenchmarkContainers.BenchmarkContainer.init
# Parameters: (upperBound = 1)

# Run progress: 50,00% complete, ETA 00:03:20
# Fork: N/A, test runs in the host VM
# *** WARNING: Non-forked runs may silently omit JVM options, mess up profilers, disable compiler hints, etc. ***
# *** WARNING: Use non-forked runs only for debugging purposes, not for actual performance runs. ***
# Warmup Iteration   1: STARTING PROFILING IN PROFILER THREAD
MOCK PEEP
1285734648,964 ops/s
# Warmup Iteration   2: 1281687199,566 ops/s
# Warmup Iteration   3: 1248636633,953 ops/s
# Warmup Iteration   4: 1286229544,274 ops/s
# Warmup Iteration   5: 1242773248,106 ops/s
Iteration   1: 1249716889,546 ops/s
Iteration   2: 1163957364,456 ops/s
Iteration   3: 1165338083,544 ops/s
Iteration   4: 1175806686,372 ops/s
Iteration   5: MOCK PEEP
1206242463,819 ops/s

Result "BenchmarkContainers.BenchmarkContainer.init":
  1192212297,547 ±(99.9%) 140077359,758 ops/s [Average]
  (min, avg, max) = (1163957364,456, 1192212297,547, 1249716889,546), stdev = 36377645,494
  CI (99.9%): [1052134937,790, 1332289657,305] (assumes normal distribution)


# JMH version: 1.32
# VM version: JDK 14.0.1, OpenJDK 64-Bit Server VM, 14.0.1+7
# VM invoker: /Users/timerdar/Library/Java/JavaVirtualMachines/openjdk-14.0.1/Contents/Home/bin/java
# VM options: -Djava.library.path=/Users/timerdar/IdeaProjects/microbenchmark_test/src/main/java/Profiling -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=50458:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8
# Blackhole mode: full + dont-inline hint
# Warmup: 5 iterations, 10 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: BenchmarkContainers.BenchmarkContainer.init
# Parameters: (upperBound = 2)

# Run progress: 75,00% complete, ETA 00:01:40
# Fork: N/A, test runs in the host VM
# *** WARNING: Non-forked runs may silently omit JVM options, mess up profilers, disable compiler hints, etc. ***
# *** WARNING: Use non-forked runs only for debugging purposes, not for actual performance runs. ***
# Warmup Iteration   1: STARTING PROFILING IN PROFILER THREAD
MOCK PEEP
1167710836,896 ops/s
# Warmup Iteration   2: 1206785568,628 ops/s
# Warmup Iteration   3: 1160517470,177 ops/s
# Warmup Iteration   4: 1192993000,343 ops/s
# Warmup Iteration   5: 1198394027,257 ops/s
Iteration   1: 1158210173,102 ops/s
Iteration   2: 1169432730,215 ops/s
Iteration   3: 1070907177,608 ops/s
Iteration   4: 336332917,114 ops/s
Iteration   5: MOCK PEEP
433452372,375 ops/s

Result "BenchmarkContainers.BenchmarkContainer.init":
  833667074,083 ±(99.9%) 1589834232,333 ops/s [Average]
  (min, avg, max) = (336332917,114, 833667074,083, 1169432730,215), stdev = 412874901,402
  CI (99.9%): [≈ 0, 2423501306,415] (assumes normal distribution)


# Run complete. Total time: 00:06:40

REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.

Benchmark                                      (upperBound)   Mode  Cnt           Score            Error  Units
BenchmarkContainers.BenchmarkContainer.geoSum             1  thrpt    5   301303141,197 ±   29045283,861  ops/s
BenchmarkContainers.BenchmarkContainer.geoSum             2  thrpt    5   226502164,323 ±   20064492,546  ops/s
BenchmarkContainers.BenchmarkContainer.init               1  thrpt    5  1192212297,547 ±  140077359,758  ops/s
BenchmarkContainers.BenchmarkContainer.init               2  thrpt    5   833667074,083 ± 1589834232,333  ops/s
THREAD 62778 PEEP
THREAD 62778 PEEP
THREAD 63451 PEEP
THREAD 63451 PEEP
THREAD 63828 PEEP
THREAD 63828 PEEP
THREAD 64242 PEEP
THREAD 64242 PEEP

Process finished with exit code 0

预期行为: 通常我希望在 Java 代码继续运行之前先执行 native 代码。但是,该程序似乎将所有代码排队,然后在基准测试完成后立即执行所有内容。

正如 this Stackoverflow Thread 所说,程序通常应该按预期工作。但我目前无法识别代码中的问题。

下图描述了我期望的程序行为:

Expected program flow

希望您能再次帮助我。

最佳答案

我在 IDE 中运行了该示例(摆脱了 native 内容)。而且它似乎工作正常。

因此,首先调用设置,然后调用基准测试,然后调用拆卸。这是您通常想要的预期顺序流程。所以我没有看到问题。

顺便说一句,我确实看到了一些并发问题。

        synchronized (PowerGadgetProfiler.profilerLock){
            try {
                System.out.println("THREAD " + Thread.currentThread().getId() + " WAITS FOR PROFILER LOCK");
                PowerGadgetProfiler.profilerLock.wait();
                PowerGadgetProfiler.running = true;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

profilerLock 等待可能会虚假失败,因此通常需要在循环中调用它。通常情况下,您还会等待分析器运行等条件;但在本例中,您正在设置条件。

所以我期待这样的事情:

synchronized (PowerGadgetProfiler.profilerLock){
      while(!PowerGadgetProfiler.running){             
          PowerGadgetProfiler.profilerLock.wait();    
      }
}

我会像这样更新PowerGadgetProfiler.running:

public static void startProfiling(){
    synchronized(profilerLock) {
        PowerGadgetProfiler.running=true;
        profilerLock.notifyAll();
    } 

当您等待探查器终止时,应该应用类似的修复。

关于java - 为什么我的 native JNI 代码是顺序运行而不是并发运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70174730/

相关文章:

java - 如何在Java中创建两个具有共享数据的数组

java - 如何从@GetMapping spring 注释中排除一些路径?

java - 使用 BatteryManager 接收广播 Intent 时出错

c - 释放 malloc 失败

安卓如何: pass and store user Input and return it back to main class(MainActivity)

java - 带有可选 Nullable 注入(inject)的 Guice @Provides 函数不起作用

c - sscanf 返回 1 读取字符串

c - 8 位架构上的 32 位操作

eclipse 中的 javacpp 不起作用——ClassNotFoundException(使用 JNI)

enums - 保持 native C++ 枚举和 Java 枚举同步