在 Java 中,是否有任何可靠的方法来确保线程彼此隔离?我有一个半星期的问题,由于静态变量和其他我无法控制的事情,实现各种第 3 方源代码的线程不断发生冲突。
我知道一个系统可以根据需要运行我正在处理的项目的多个实例。但是,当尝试将所有内容合并到一个线程化的单个可执行文件中时,总是会出现错误和异常。
我几乎要为我想要的这个程序的每个实例启动一个新进程,但我真的不想走这条路(它也会消除我收集的大量实时数据阻碍我杀死目标进程的能力)。
建议?谢谢!
在 Java 中,是否有任何可靠的方法来确保线程彼此隔离?我有一个半星期的问题,由于静态变量和其他我无法控制的事情,实现各种第 3 方源代码的线程不断发生冲突。
我知道一个系统可以根据需要运行我正在处理的项目的多个实例。但是,当尝试将所有内容合并到一个线程化的单个可执行文件中时,总是会出现错误和异常。
我几乎要为我想要的这个程序的每个实例启动一个新进程,但我真的不想走这条路(它也会消除我收集的大量实时数据阻碍我杀死目标进程的能力)。
建议?谢谢!
如果您要使用的库的作者没有将他们的代码设计为线程安全的,那么除了防止两个线程同时调用它之外,您几乎无能为力。
您可以使用类加载器来发挥一些技巧,但这往往会导致一个全新的复杂世界。详细地说,如果您使用不同的类加载器,可以将同一个类两次(或多次)加载到同一个 JVM 中 - 因此您可以有效地获得静态变量的独立副本。一些 Java EE 应用程序服务器利用了这种单独的类加载器的使用。这反过来又导致了当库本身开始进行一些反射和动态类加载时使用哪个类加载器和类路径的问题。除非您的需求非常大,否则我不会推荐这种方法。
按偏好将是:
1)。为不安全的代码设置一个单线程工作者。尝试在你的多线程应用程序中做尽可能多的工作,尽可能少地进入 Worker。
2)。如果工作人员是您处理的主要部分,因此您确实需要并行执行将工作人员拉出到多个单独的进程中,请使用一些 IPC 通信来共享工作。这感觉就像 JMS 排队解决方案可能会很好地工作。
3)。如果您负担不起IPC开销,请尝试寻找线程安全的库替代方案,或者如果您对作者有影响,请让他们修复代码。增加它们的并行度真的不应该那么难。
由于静态变量和其他我无法控制的事情,实现各种第 3 方源代码的线程不断发生冲突。
如果确实如此,那么我认为您必须走上拥有单独流程的道路。如果您调用的代码不是线程安全的,那么您所能做的就是确保一次仅由一个进程调用此代码。这基本上消除了在不同线程中运行它的优势。
以及阻碍我杀死目标进程的能力
我在这里看不到你的意思。只有使用进程才能安全地终止处理,如果您无法完全控制所有正在运行的代码,则不可能以安全的方式使用线程执行此操作。
另请参阅此问题以讨论类似问题。
您的要求已在 2006 年获得批准的JSR-121中涵盖。
我没有听到太多关于 JSR-121 实现的信息,但快速搜索后我找到了http://weblogs.java.net/blog/gczaj/archive/j2se/index.html。
不幸的是,没有办法做到这一点。如果线程访问共享资源,它们应该根据需要锁定这些资源,否则您的程序肯定会面临共享状态的损坏。
也许您可以以允许您同步访问的方式包装对共享资源的访问?
我几乎要为我想要的这个程序的每个实例启动一个新进程,但我真的不想走这条路(它也会消除我收集的大量实时数据阻碍我杀死目标进程的能力。)
听起来,您尝试重用的代码实际上并非设计用于多线程应用程序。在这种情况下,为每个实例启动一个单独的进程实际上可能是您的最佳选择。与其阻碍你杀死每个实例的能力,它实际上应该让这更容易做到;见Process.destroy()
。
虽然不清楚您所说的“实时”是什么意思,但如果每个子进程都写入其标准输出,您可以编写控制程序以在写入时读取和整理输出。
您可以为每个线程使用单独的类加载器,以加载您想要分开的第三方库。
您可以尝试将资源放在单个执行程序中,这样您将永远不会让其中两个进程并行运行。
你可以通过执行者来做到这一点:
class Foo {
private ExecutorService executor = Executors.newSingleThreadExecutor();
public void addTask(Runnable bar) {
executor.submit(bar);
}
}