我正在编写Java程序的过程中,我正处于调试并发问题的阶段,而不是我想要处理的问题。
我不得不问:在精神上设置你的程序时,你如何处理并发问题?在我的情况下,这是一个相对简单的游戏,但线程问题不断出现 - 任何快速修复几乎肯定会导致一个新的问题。
用非常笼统的术语来说,在决定我的应用程序如何“流动”而我的所有线程都没有结束时,我应该使用哪些技巧?
答案 0 :(得分:6)
并发归结为管理共享状态。
“所有并发问题归结为 协调对可变状态的访问。 可变性越小,越容易 是为了确保线程安全。“ - Java Concurrency in Practice
所以你必须问自己的问题是:
管理共享状态的最简单方法是序列化每个操作。然而,这种粗粒度的方法导致高锁争用和差的性能。管理并发可以看作是一种优化练习,您可以尝试减少争用。所以后续问题是:
许多减少争用的方法依赖于某种形式的权衡在强制执行正确行为和减少争用的可行性之间。
请注意,我从未参与游戏,只在企业应用程序的服务器端部分工作。我可以想象它可能会有很大不同。
答案 1 :(得分:5)
我尽可能使用不可变数据结构。关于我唯一一次使用可变结构的时候,就像我需要一个可以节省大量工作的库一样。即使这样,我也尝试将该库封装在一个不可变的结构中。如果事情无法改变,那就不用担心了。
我应该补充一点,关于你未来的努力要记住的一些事情是STM和演员模型。这两种并发方法都显示出非常好的进展。虽然每个都有一些开销,但取决于程序的性质可能不是问题。
编辑:
以下是您可以在下一个项目中使用的一些库的一些链接。有Deuce STM顾名思义是Java的STM实现。然后是ActorFoundry,顾名思义是Java的Actor模型。但是,我不禁用Scala使用内置的Actor模型制作插件。
答案 2 :(得分:5)
阅读并发性,或者更好的是,如果你还在大学,那就参加并行编程的研究生课程。见The Java Tutorials: Lesson: Concurrency。一本着名的Java并发书是Java Concurrency in Practice。 Java已经内置到框架中以处理并发问题,包括concurrent collections和synchronized
methods。
答案 3 :(得分:2)
您拥有的线程越少,他们共享的状态越小,他们在此共享状态下的交互模式越简单,您的生活就会越简单。
你说Lists正在抛出ConcurrentModificationException。我认为你的列表是由单独的线程攻击的。所以你要问自己的第一件事是这是否必要。第二个线程是否无法对列表的副本进行操作?
如果线程确实需要同时访问列表,则在整个遍历期间锁定列表可能是一个选项(如果通过除此之外的任何其他方式修改列表,则迭代器无效迭代器)。当然,如果您在遍历列表时执行其他操作,则此遍历可能需要很长时间,而锁定其他线程可能会威胁到系统的活跃性。
另请注意,如果列表是共享状态,其内容也是如此,因此如果您打算通过复制列表来绕过锁定,请确保执行深层复制,或者证明列表中包含的对象是他们自己的线程安全。
答案 4 :(得分:2)
对于您提到的ConcurrentModificationExceptions,您的应用程序的多线程特性可能是一个红色的鲱鱼:还有其他方法可以获得不一定涉及多个线程的ConcurrentModificationException。 请考虑以下事项:
List<Item> items = new ArrayList<Item>();
//... some code adding items to the list
for (Item item : items) {
if(item.isTheOneIWantToRemove()) {
items.remove(item); //This will result in a ConcurrentModificationException
}
}
使用迭代器或增加索引值将for循环更改为循环可以解决问题:
for (Iterator<String> it = items.iterator(); it.hasNext();) {
if(item.isTheOneIWantToRemove()) {
it.remove(); //No exception thrown
}
}
或
for (int i = 0; i < items.size(); i++) {
if(item.isTheOneIWantToRemove()) {
items.remove(items.get(i)); //No exception thrown
}
}
答案 5 :(得分:1)
从设计的角度来看,我发现绘制序列图很有用,其中每个线程的动作都是彩色编码的(也就是说,每个线程都有自己的颜色)。以这种方式使用颜色可能是序列图的非标准使用,但它有助于概述线程如何以及在何处进行交互。
正如其他人所提到的那样,将设计中的线程数量减少到绝对最小值,它需要正常工作也会有很大帮助。
答案 6 :(得分:0)
这取决于你的线程做什么。通常程序有一个主线程,可以思考和工作线程执行并行任务(定时器,在GUI上处理长计算等)但您的应用程序可能不同 - 这取决于您的设计。你用什么线程?您有什么锁来保护共享数据结构?如果您使用多个锁,您是否有一个锁定以防止死锁的订单?
答案 7 :(得分:0)
答案 8 :(得分:-1)
在设计应用程序时,我建议考虑共享哪些程序资源。本文深入介绍了各种线程之间如何共享各种Java资源:
http://javatip.com/2010/07/core-java/concurrency/thread-safe-without-synchronization