主线程和单个长时间运行的线程之间的线程安全双向通信



我有一个应用程序,它有一个类/进程,它使用基于 C 的第三方本机库执行一些繁重的工作。此库有一些自己的依赖项和数据,它在第一次运行时加载到内存(接近 500MB(中。加载需要几秒钟,因此只需要发生一次。此控件类还生成从与本机库一起使用的数据库中提取的对象的大型哈希图。

我的问题是这个。控制类需要更新大型哈希图并在外部引用。例如:当外部有更新时,哈希映射中的相关对象需要更新其内容,当主线程需要使用哈希映射中的特定对象时,它需要访问它或它的副本。我一直说"主线程",但现实情况是应用程序的主要部分使用来自另一个多线程本机库的事件侦听器。新事件来得很快(在每秒 100 到 200 个的范围内,并且在生产中可能会更高(。

我需要的是一种来回传递数据的线程安全方式。我的第一个想法是使用单例,这适用于少量请求(每秒 15 个(,但一旦增加,我就遇到了导致 JVM 崩溃的线程问题。我的下一个想法是使用阻塞队列,但据我所知,没有办法可靠地进行双向通信。

让我解释一下最后一句话(我知道取消排队(。必须发生的是,当一个进程对控制类说"我需要对象 74"时,它需要能够返回对象 74。如果两个单独的进程请求一个对象(例如 74,另一个请求 89(,则无法保证每个进程都会获得正确的对象,则取消排队。至少在事后它收到对象并检查它是哪一个之前。

接下来,我考虑了应用程序本身中的事件侦听器模式。基本上,主逻辑类(发送更新和请求副本的逻辑类(会将自身的引用传递给控制器类,控制器类将实现@Override方法。我什至不确定这是否是一个好主意,但我什至没有走多远,就意识到它也不是线程安全的。

所以我被困在试图思考在这里工作的设计模式。通常我可以解决这类问题,但最近家人去世让我盯着屏幕没有任何解决方案。我知道这是一个古老的问题,已经解决了一百万次,但我现在无法完成这个过程。

任何帮助,不胜感激。

感谢圣安大略省(在上面的评论中(,我找到了解决方案。

我尝试的第一件事是ConcurrentHashMap,但由于第三方库的非线程安全性质,我再次猜测自己。

最终,解决方案是隔离本机库并在自己的线程中运行它。我通过 BlockingQueue 将数据传递到本机库。所以在我的代码的其他地方,我只使用 myQueue.put(data( 调用来传递数据。这现在运作良好。

下面是本机库线程代码的外观:

public void Start() {
Runnable task = () -> {
try {
/* SETUP NATIVE LIBRARY */
} catch (Exception e) {
e.printStackTrace();
}
while (keepRunning) {
while (!myQueue.isEmpty()) {
Process_Run();
}
try {
Thread.sleep(20);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
myThread = new Thread(task); // Run the task in a background thread
myThread.setDaemon(true); // Terminate the running thread if the application exits
myThread.start(); // Start the thread
}
private void Process_Run() {
try {
MyCustomData myData = myQueue.take();
/*  DO STUFF  */
} catch (Exception e) {
e.printStackTrace();
}
}

最新更新