多线程访问的静态方法,Java

时间:2010-03-05 14:04:37

标签: java multithreading static thread-safety static-methods

我正在使用第三方库对7张牌扑克牌进行手牌评估。此库中的方法evaluate被声明为public static,我相信它会改变类中的一些全局静态数组。我遇到的问题是,当我正在进行大约10米枚举的枚举算法时,我想并行化它,因此我创建了FutureTasks,每个都评估了10米评估的一小部分。我得到的错误是:

java.util.concurrent.ExecutionException: java.lang.ArrayIndexOutOfBoundsException: -2147483648
    at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
    at java.util.concurrent.FutureTask.get(Unknown Source)

在尝试检索因抛出异常而中止的任务结果时,会从Google搜索中收集到的内容。

是否有某种方法可以使这个静态方法线程安全,就像每个线程制作自己正在编辑的全局静态数组的副本一样?

由于

8 个答案:

答案 0 :(得分:3)

可以在每个线程的单独ClassLoader中加载库,以确保每个类都有自己的类集,因此也有自己的一组静态变量。

如果这样做,您必须小心确保这些类加载器的父类加载器无法访问该库。

答案 1 :(得分:2)

如果您可以修改代码,则可以创建静态变量thread local,但听起来您不能修改代码的这一部分。更多关于thread local storage(维基百科)

答案 2 :(得分:1)

使用evaluate方法

上的同步方法修饰为库创建单例实例包装器
public final class SynchronizedHandEvaluator {
    private static final SynchronizedHandEvaluator INSTANCE = new SynchronizedHandEvaluator();
    public static final getInstance() {
      return INSTANCE;
    }
    private SynchronizedHandEvaluator() { }

    public synchronized int evaluate(Card[] hand) {
        return ExternalLibrary.evaluate(hand);
    }
}


// then just use the wrapper as you would expect
int result = SynchronizedHandEvaluator.getInstance().evaluate(hand);

答案 3 :(得分:0)

您是否安全地在阵列上操作?你能更好地解释你的代码结构吗?你是如何划分工作的?为什么算法需要修改全局数组?

无论如何,使用ForkJoin或CyclicBarrier / Phaser来分割工作会更有意义吗?

答案 4 :(得分:0)

如果有多个线程使用共享状态(全局静态数组)访问某个方法,则需要确保以线程安全的方式访问它们。

这意味着当您从这些数组读取时以及写入数据时都需要同步/锁定它们。

听起来,只是来自你的堆栈跟踪,你不是。

如果可能,我建议最小化或消除线程之间共享的状态量。

答案 5 :(得分:0)

您无法使其成为线程安全的,但您可以同步对库的访问:

static Object globalLock = new Object();

synchronize (globalLock) {
  evaluate();
}

这意味着,当然,一次只有一个线程可以执行此方法。因此,如果您的程序在该方法上花费了大量时间,那么它对您没有帮助。

或者,您可以使实例在单独的进程中运行。但是在进程之间建立通信(通过RMI或类似方法)是非常痛苦的。

如果您访问源代码,唯一的另一个选择是重写它。您必须将所有静态字段移动到单个上下文类中,然后确保用于访问静态字段的所有代码都引用了新上下文类的实例。

已经提到的ThreadLocal机制可以帮助您解决这个问题,因为它是一种特殊的引用,它看起来与每个线程不同。这可以使您免于修改方法签名以将实例传递给上下文对象。恕我直言,将上下文传递给方法可能更干净。利用现代IDE的重构功能,这并不难。

答案 6 :(得分:0)

使用ConcurrentLinkedQueueCollections#synchronizedList()代替数组。它的访问是内部同步的。

答案 7 :(得分:0)

有数百万只手要评估,现在看Java Distributed Computing永远不会太早。

当您考虑另一个good suggestion时,您可以将评估程序包装在一个简单的单线程服务器中,并在资源允许的情况下启动尽可能多的JVM。

最后,考虑编写自己的评估者;你可以测试你现有的,你的可能会更好!