2010-03-05 85 views
2

我正在使用第三方库对7张牌扑克手进行手牌评估。该库中的方法evaluate被声明为公共静态,我相信它会改变类中的一些全局静态数组。我遇到的问题是,因为我正在做一个大约10m枚举的枚举算法,所以我要创建FutureTasks,每个评估10m评估的一小部分。我得到的错误是:静态方法被多线程访问,Java

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) 

从我从谷歌搜索收集哪些试图检索中止通过抛出异常的任务的结果时造成的。

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

感谢

+3

我可能会沿着“XX.evaluate()不是线程安全的”的方式打开一个针对库的增强bug。这是假设图书馆有一些错误跟踪,并积极维护。否则,如果该库是开源的,你可以自己修复它,并向开发者提供补丁并使用你的补丁版本。 – 2010-03-05 14:23:58

+0

它只发布而不改变它 – Aly 2010-03-05 14:31:05

+2

你确定图书馆没有试图保持状态来记住哪些卡片已被处理/显示,并使用该信息为一只手提供更准确的“价值”? – ptomli 2010-03-05 14:32:43

回答

1

与evaluate方法

​​
2

如果你可以修改代码,你可以使静态变量thread local,但它不喜欢你的声音可以修改这部分代码。更多关于thread local storage(维基百科)

+0

什么是线程局部的,它是否具有和使变量和方法非静态的优点。我这样说,因为我可能能够获得源代码 – Aly 2010-03-05 14:11:02

+1

检查链接。线程本地静态变量是线程本地的静态变量(即每个线程都有它自己的值,但否则它表现为静态)。 – Kris 2010-03-05 14:14:45

+0

@Aly如果你可以获得源代码,那么你只需要在评估方法声明(以及任何其他可改变受影响静态的公共访问方法)中添加'synchronized'关键字。 – ptomli 2010-03-05 14:34:18

3

可能加载库中为每个线程单独ClassLoader,以确保每个类都有自己的一套类,因此它自己的一套静态变量。

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

+1

你能提供一个小玩具的例子吗? – Aly 2010-03-05 14:18:50

+0

另请参见http://java.sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html – trashgod 2010-03-05 15:33:52

0

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

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

+0

我没有在数组上操作,我在第三方库中调用静态方法在非线程安全的庄园中对阵列进行操作 – Aly 2010-03-05 14:28:59

0

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

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

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

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

0

你不能让线程安全的,但你可以访问库同步:

static Object globalLock = new Object(); 

synchronize (globalLock) { 
    evaluate(); 
} 

这意味着,当然,只有一个线程可以同时执行此方法。所以如果你的程序在这种方法上花费了很多时间,它不会对你有所帮助。

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

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

已经提到ThreadLocal机制可以帮助你,因为它是一种特殊类型的引用,看起来不同于每个线程。这可以使您免于修改方法签名以将实例传递给上下文对象。恕我直言,它可能是清洁的只是将上下文传递给方法。有了现代IDE的重构功能,并不难做到。

0

随着数百万手的评价,它永远不会太早看Java Distributed Computing

当您考虑其他good suggestion时,您可以将评估程序包装在一个简单的单线程服务器中,并启动尽可能多的JVM。

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