Java 通过JNI实现GraphViz库的线程安全使用

Java 通过JNI实现GraphViz库的线程安全使用,java,multithreading,java-native-interface,graphviz,Java,Multithreading,Java Native Interface,Graphviz,我试图在Linux下的一个REST服务中使用GraphViz 2.40.1来展示图形。该服务是一个JavaSpring引导应用程序。我目前的方法是将共享库加载到我的JVM中,并使用库cgraph和gvc中的函数通过JNI调用本机代码。我希望在内存中执行所有操作并避免文件I/O。但我已经在GraphViz库指南中阅读了以下警告,该指南在第1节末尾以粗体印刷:“N.B.将GraphViz用作库不是线程安全的。” 我正在寻求有关我应该从该声明中得出的后果的帮助。没有提供细节。例如,我可以想象,对于图形

我试图在Linux下的一个REST服务中使用GraphViz 2.40.1来展示图形。该服务是一个JavaSpring引导应用程序。我目前的方法是将共享库加载到我的JVM中,并使用库cgraph和gvc中的函数通过JNI调用本机代码。我希望在内存中执行所有操作并避免文件I/O。但我已经在GraphViz库指南中阅读了以下警告,该指南在第1节末尾以粗体印刷:“N.B.将GraphViz用作库不是线程安全的。

我正在寻求有关我应该从该声明中得出的后果的帮助。没有提供细节。例如,我可以想象,对于图形解析中发生的错误,保持可变状态的函数不是线程安全的,但我不使用这些函数。我只使用以下功能:
cgraph中的agmemread
agclose
,以及gvc中的
gvfreellayout
gvParseArgs
gvLayout
gvFreeRenderData
gvfreellayout
。我只在Java、本地变量和方法参数中缓存任何内容。这种对库的使用是线程安全的吗

如果不是,非线程安全性是否只影响单个函数的使用,而不影响跨函数的使用?那么,让我的Java本机方法
静态同步
就足够了吗?或者我必须对每个REST请求进行同步

或者,我可以为每个请求派生一个新的操作系统进程,并使用GraphViz的dot程序Runtime.exec()执行文件操作


什么方法可以最好地扩展?

顺便说一句,我在GitLab上搜索了GraphViz问题,找到了问题1282。其中的一条评论指出:“许多函数依赖于静态全局或局部变量,从lexer和parser开始,包括许多布局阶段和实用算法,直到输出。为了安全起见,对所有这些的访问都需要通过锁进行保护,或者转换为作为参数传递给函数的显式状态数据。”但这是2岁。尽管这个问题仍然悬而未决,但也许从那时起GraphViz内部发生了很大变化。我会担心的。每个JVM实例只会获得一个库的副本,因此该库中的任何全局内存只存在一次。如果您的web服务器运行的是持久性JVM(可能是),我会担心多个并发请求会导致全局变量出现问题。您可以围绕这个库的jni用法使用一个信号量来解决这个问题,或者将这个库作为一个单独的进程来处理,这样就只能使用一个实例。通过JNI调试线程安全问题并不有趣。感谢您的警告,我将在单独的过程中继续使用lib。顺便说一句,我在GitLab上搜索了GraphViz问题,并找到了问题1282。其中的一条评论指出:“许多函数依赖于静态全局或局部变量,从lexer和parser开始,包括许多布局阶段和实用算法,直到输出。为了安全起见,对所有这些的访问都需要通过锁进行保护,或者转换为作为参数传递给函数的显式状态数据。”但这是2岁。尽管这个问题仍然悬而未决,但也许从那时起GraphViz内部发生了很大变化。我会担心的。每个JVM实例只会获得一个库的副本,因此该库中的任何全局内存只存在一次。如果您的web服务器运行的是持久性JVM(可能是),我会担心多个并发请求会导致全局变量出现问题。您可以围绕这个库的jni用法使用一个信号量来解决这个问题,或者将这个库作为一个单独的进程来处理,这样就只能使用一个实例。通过JNI调试线程安全问题并不有趣。感谢您的警告,我将在单独的过程中继续使用lib。