2015-07-10 61 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的一個實例上。另外,最好在私有對象上使用同步,而不是從安全角度來看使用同步。 –