【问题标题】:Thread isolation in JavaJava中的线程隔离
【发布时间】:2023-03-07 15:45:01
【问题描述】:

在 Java 中是否有任何可靠的方法来确保 线程 彼此隔离?我有一个半星期的问题,由于静态变量和其他我无法控制的事情,实现各种第 3 方源代码的 线程 不断发生冲突。

我知道一个系统可以根据需要运行我正在处理的项目的多个实例。但是,当尝试将所有内容合并到一个线程化的单个可执行文件中时,总是会出现错误和异常。

我几乎要为我想要的这个程序的每个实例启动一个新的进程,但我真的不想走这条路(它会消除很多我收集的实时数据,以及阻碍我杀死目标进程的能力)。

建议?谢谢!

【问题讨论】:

    标签: java multithreading process isolation


    【解决方案1】:

    如果您要使用的库的作者没有将他们的代码设计为线程安全的,那么除了防止您的两个线程同时调用它之外,您几乎无能为力。

    您可以使用类加载器来发挥一些技巧,但这往往会导致一个全新的复杂世界。详细地说,如果您使用不同的类加载器,可以将同一个类两次(或多次)加载到同一个 JVM 中 - 因此您可以有效地获得静态变量的独立副本。一些 Java EE 应用程序服务器利用了这种单独的类加载器的使用。这反过来又导致了当库本身开始进行一些反射和动态类加载时使用哪个类加载器和类路径的问题。除非您非常需要,否则我不会推荐这种方法。

    按偏好为:

    1)。为不安全的代码设置一个单线程工作者。尝试在您的多线程应用程序中做尽可能多的工作,尽可能少地放入 Worker。

    2)。如果工作人员是您处理的主要部分,因此您确实需要并行执行将工作人员拉出到多个单独的进程中,请使用一些 IPC 通信来共享工作。这感觉就像 JMS 排队解决方案可能会很好地工作。

    3)。如果您负担不起IPC 的开销,请尝试找到一个线程安全的库替代方案,或者如果您对作者有影响,请让他们修复代码。增加它们的并行度真的不应该那么难。

    【讨论】:

      【解决方案2】:

      由于静态变量和其他我无法控制的事情,实现各种第 3 方源代码的线程不断发生冲突。

      如果情况确实如此,那么我认为您必须走这条拥有独立流程的道路。如果您调用的代码不是线程安全的,那么您所能做的就是确保一次仅由一个进程调用此代码。这基本上消除了在不同线程中运行它的优势。

      还会阻碍我杀死目标进程的能力

      我不明白你的意思。只有使用进程才能安全地终止处理,如果您无法完全控制所有正在运行的代码,则不可能以安全的方式使用线程执行此操作。

      有关类似问题的讨论,另请参阅 this question

      【讨论】:

        【解决方案3】:

        您的要求已在 2006 年获得批准的 JSR-121 中涵盖。

        我没有听到太多关于 JSR-121 实现的信息,但快速搜索后我找到了http://weblogs.java.net/blog/gczaj/archive/j2se/index.html

        【讨论】:

          【解决方案4】:

          不幸的是,没有办法做到这一点。如果线程访问共享资源,它们应该根据需要锁定这些资源,否则您的程序肯定会面临共享状态的损坏。

          也许您可以以一种允许您同步访问的方式包装对共享资源的访问?

          【讨论】:

            【解决方案5】:

            您可以为每个线程使用单独的类加载器,以加载您想要保持独立的第三方库。

            【讨论】:

              【解决方案6】:

              我快到了 为每个人启动一个新流程 我想要的这个程序的实例, 但我真的不想这样做 路线(它会消除很多 我收集的实时数据,以及 阻碍我杀死目标的能力 过程。)

              听起来,您尝试重用的代码实际上并非设计用于多线程应用程序。在这种情况下,为每个实例启动一个单独的进程实际上可能是您的最佳选择。与其阻碍你杀死每个实例的能力,它实际上应该让这更容易做到;见Process.destroy()

              虽然不清楚您所说的“实时”是什么意思,但如果每个子进程都写入其标准输出,您可以编写控制程序来读取和整理写入的输出。

              【讨论】:

                【解决方案7】:

                您可以尝试将资源放在一个执行程序中,这样您就永远不会让其中两个进程并行运行。

                你可以通过执行者来做到这一点:

                class Foo {
                  private ExecutorService executor = Executors.newSingleThreadExecutor();
                
                  public void addTask(Runnable bar) {
                    executor.submit(bar);
                  }
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-03-23
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-08-19
                  • 2016-05-06
                  • 1970-01-01
                  相关资源
                  最近更新 更多