2013-04-30 84 views
2

我在繪畫方面遇到了一些沉重的優化問題。我的代碼示例如下所示:優化:繪畫同步

BufferedImage img1; 
synchronized(game.players){ 
    synchronized(game.monsters){ 
     synchronized(game.playersHealth){ 
      synchronized(game.monstersHealth){ 
       synchronized(game.overlays){ 
        synchronized(game.projectiles){ 
         img1 = game.drawAll(); 
        } 
       } 
      } 
     } 
    } 
} 
game.setImage(img1); 
game.repaint(); 

我知道這對大多數人來說可能看起來很可怕。問題是,我有多個包含數據的不同對象集合(玩家,怪物等),並且這個代碼塊^在一個單獨線程的'無限'循環中運行,該線程組織所有圖像,然後告訴遊戲再次繪畫自己。我需要幫助。你們能否指引我朝正確的方向做正確的事情?

+1

噢,我的....也許同步上課?也許用'Thread.yield()'? – jn1kk 2013-04-30 20:59:02

+0

程序中使用了其他什麼鎖定順序?例如,一段代碼是否曾經同步過'game.projectiles'而沒有先鎖定'overlays','monstersHealth'等?如果沒有,那麼將所有這些混亂集中到一個鎖中。 – 2013-04-30 20:59:45

+0

是的,還有代碼的其他部分只與一個或兩個字段同步。但是,如果我只想訪問投射物或其他東西,那麼與所有字段同步效率會不會更低? – Blackvein 2013-04-30 21:03:09

回答

1

請注意​​關鍵字:它僅用於提供對給定對象的鎖定的獨佔訪問權限。如果沒有其他代碼段試圖在同一個鎖上進行同步,那麼只有執行該特定代碼段的線程將會同步

這意味着:

  • 您的其他線程必須鎖定任何這些藏品的針對操縱該集合中的一個或多個元素的語句。
  • 唯一被鎖定的是集合:如果T位於同步塊之外,則保持對元素的引用的線程T仍然可以在執行同步代碼的同時將其修改爲渲染線程R.

現在,關於您的代碼,一種解決方案是通過鎖定各個對象,在渲染函數內向下推送同步。你可能在每個集合上都有一個循環,它們逐個處理元素,或者是某種特定的效果:這就是你可能想要進行同步的地方,或者也許是在元素本身中。例如,您可以將遊戲邏輯從遊戲渲染中分離出來,方法是讓每個遊戲實體都實現兩個接口:渲染和邏輯,並讓渲染線程只訪問渲染接口,然後邏輯遊戲訪問邏輯接口。

通過在特定接口中分離兩個問題,您可能能夠更好地區分哪些信息被使用了哪些信息,以及哪些信息需要正確同步。

另一種解決方案,可能涉及更少的重構,包括將邏輯和呈現線程轉換爲生產者使用者設置:每個線程都通過實體列表工作,並在完成時將其推送到其他線程隊列。每個實體都會在線程之間來回移動,並讓線程在它們各自的輸入隊列之外沒有任何其他形式的同步。

如果您在每個線程上有不同的排序約束,那麼除了嘗試重新組合依賴組中的實體並分批處理它們(線程處理一個批處理,並將該批處理作爲單個項目到另一個線程隊列),即。嘗試分離不相互依賴的實體。

+0

如果不知道更多關於設置的信息,將很難進入更精細的細節。 – didierc 2013-04-30 23:57:34