2015-07-10 60 views
0

我有一个OpenGL ES 2.0应用程序。内它,我有一个包含像这样另一类型的对象的一个​​阵列(这被简化为问题)的类:Java:保护一个对象不被多线程访问

public class StoreList(){ 

thisList StoreItems[]; 

    public StoreList(int nuberOfItems){ 

     thisList = StoreItems[numberOfItems]; 

    } 

} 

最初,我该应用中填充列表,然后在某些点(当用户在“存储”场景),它可能被添加到列表中的新项目,因此,举例来说,这个名单可以是这个样子:现在

Before    After inserting object 'Fish' into index 1 

Index 0 - Dog  Index 0 - Dog 
Index 1 - Fox  Index 1 - Fish 
Index 2 - Bird  Index 2 - Fox 
Index 3 - Snake Index 3 - Bird 
        Index 4 - Snake 

,这个名单是通过迭代出于各种原因。例如,用于渲染,更新它们的位置等。

我遇到的问题是,我的应用程序使用2个线程 - GL渲染线程和Main/UI线程。

当用户执行某个动作时,UI线程调用插入额外项目的'insertObject'方法,如上所述。然而,渲染线程很乐意做它的事情,如果它是在索引1处同时渲染对象'insertObject'被调用,那么它开始导致问题(列表中的每个对象具有不同数量的openGL四边形来绘制并且绘制的数字包含在对象本身的一个变量中),所以如果索引1处的原始对象有5个四边形,并且新对象只有4个,那么它开始尝试绘制第五个四边形,并且我们得到所有问题的方式(索引超出范围)。

render方法,updateLogic方法和onTouchEvent方法都被声明为synchronized,但我仍然遇到这个问题。

我不确定如何去确保这个对象(StoreList的实例及其中的所有内容,它是'thisList'数组)只能从一个线程一次更新。

我看到的有关并发问题的问题都是关于保护一个方法不被多线程而不是对象调用,所以我有点困惑。

希望得到任何指导。

+2

也许一个['CopyOnWriteArrayList'](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html)会更适合你吗? – RealSkeptic

+1

最简单的方法:通过['Lock'](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Lock.html)保护列表。每个想要读取或写入列表的方法都需要首先获取“Lock”。稍微复杂一些:尝试使用['@ synchronized'](https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html)。只要'@ synchronized'内没有使用阻塞结构(比如'wait()'),就可以完成这项工作。 – Turing85

+0

Thanks @ Turing85,你的意思是在所有将从列表中读/写的代码上使用同步块? (使用列表本身作为锁定对象?)我只是想知道我是否可以简单地声明任何读取/写入列表的同步方法?我刚刚那样做,迄今没有崩溃(经过大约30次测试)。我也不确定你的意思是'@synchronized'。你能提供一个例子吗?谢谢你的帮助。 – Zippy

回答

0

为什么不在StoreItems上使用同步块而不是同步插入/更新方法。同步块将保证只有一个线程可以执行插入代码块,或者任何时间在同一对象(即StoreItems)上同步的任何其他代码块(比如更新)。

+1

标记为synchronized的方法不锁定方法,它们锁定对象的实例(如果它们是实例),如果它们是静态的,则锁定在类上。所以他们已经锁定了同一个对象。 –

+0

感谢@RahulPrasad,有什么理由更喜欢声明方法同步的同步块吗? – Zippy

+1

正如Mark在上面的评论中指出的那样,通过同步方法,我们将获得对完整实例对象的锁定,这意味着当线程正在运行任何同步方法时,没有其他线程可以在此实例对象上使用任何同步方法。在你提供的代码片段和提出的问题中,强调了类成员“StoreItems”;因此我建议在StoreItems上使用synchronized块并在它上面获取一个锁而不是在StoreList的一个实例上。另外,最好在私有对象上使用同步,而不是从安全角度来看使用同步。 –