2012-03-31 43 views
2

我正在寫一個遊戲,其中一個線程的線程之間共享的數據同步再一次。我也有一個特製的事件處理程序與按鍵等如何使用暫停,然後恢復或替代

這一切工作在大多數情況下細交易。不過,如果GameThread渲染時引發事件,則會出現問題。在極少數情況下,處理事件的處理程序可能會對需要渲染的內容進行併發更改,以影響GameThread渲染的結果。

爲了避免這種情況,我想事件處理程序,立即暫停GameThread,處理事件,然後恢復GameThread。

  1. suspend()/resume()方法適合我的需要,但他們被棄用。然而,就我而言,由於死鎖的可能性很小,不管使用它們是否安全?

  2. 如果沒有,我有什麼其他選擇沒有一個巨大的開銷的金額是多少?

我看到了一個建議,要求線程暫停在線程中設置一個標誌暫停。然而,就我而言,我並不認爲這是一個可行的選擇,因爲GameThread循環在循環迭代期間可能需要一段時間。在完成循環之前,我將無法檢查標誌,屆時已經太晚了。

我需要立即暫停,否則用戶會注意到事件處理的延遲。

+4

不推薦使用暫停/恢復的原因是因爲很難暫停/恢復線程權限,並且由應用程序開發人員來處理。帶有共享標誌的解決方案是最常用的。你可以發佈一些示例代碼 - 我認爲可以使用標誌並且仍然具有響應式應用程序。 – 2012-03-31 03:06:24

回答

0

suspend()/ resume()方法適合我的需求,但它們已被棄用。然而,就我而言,由於死鎖的可能性很小,不管使用它們是否安全?

顯然,如果有零陷的機會,那麼它是安全的。但是有各種意想不到的方法來解決僵局。例如,你可能會在初始化一個類的時候暫停一個線程......並且會導致任何其他嘗試引用該類的靜態字段的線程死鎖。 (這是JVM的特定行爲的結果,還有其他地方沒有指定引擎蓋下的鎖定/同步,這是不夠的,除非你打算使用這些過時的方法。)

所以,現實的情況是,這是真的很難確定(證明),如果它實際上是安全的。如果你不能確定這一點,那麼這是一個潛在的風險事情。這就是爲什麼這些方法已被棄用。

(嚴格地說,這不是一個死鎖。死鎖是當線程可以永遠繼續。在這種情況下,如果您可以繼續執行暫停的線程,則其他線程可以繼續。)

1

如果您要同步對資源的訪問,使用的ReentrantLock:

的ReentrantLock同步=新的ReentrantLock();

您必須將該鎖傳遞給您想要訪問共享數據的每個可運行對象。

然後在你所訪問相關資源的每個地方,你會使用共享鎖對象,獲取和釋放鎖(即你的關鍵段):

sync.lock(); 

try { 
    // critical section code here 
} 
finally { 
    sync.unlock(); 
} 

這是非常標準Java中的併發編程。請記住「鎖定」是一個阻塞方法,所以你可能需要使用「的tryLock」,它可讓您嘗試獲取鎖,但返回一個布爾值,以你是否真正得到了鎖:

if (sync.tryLock()) { 
    try { 
    //critical section 
    } 
    finally { 
    sync.unlock(); 
    } 
} 

有「的tryLock」,這將等待給定的時間量,前,將放棄嘗試獲取鎖,並返回一個錯誤值的版本。

1

通常情況下,你會做一些線程同步:

這將讓你做的,你正在做的兩件事情:要麼在遊戲中渲染線程渲染或做根據您的事件進行更改。

你所面臨的問題似乎是,你的渲染代碼花費的時間太長了,你實際上有一個流暢的體驗(即很多事件都可以堆積起來進行處理,同時要渲染的東西)。在這種情況下,你應該使你的渲染不再是獨立的部分,可以快速完成並同步它們。

無需任何代碼,我不能給你一個具體的建議,但在總體上會是這個樣子:

List<Shape> shapesToRender; 
Object lockObject = new Object(); // Note this must be somehow shared between two threads 

// Your rendering thread method 
public void renderForever() { 
    while(true) { 
    for(Shape shape: shapesToRender) { 
     synchronized(lockObject) { 
     render(shape); 
     } 
    } 
    } 
} 

// One of your event handlers 
public void handleEvent(Event event) { 
    synchronized(lockObject) { 
    // Process event somehow, e.g. change the color of some of the shapes 
    event.getShape().setColor(Color.RED); 
    } 
} 

通過以上,或者:

  • 你會被渲染一個形狀(和你的所有事件處理程序將等待一個完成),或
  • 你的一些事件處理程序會做什麼(你的渲染線程將等待一個完成)

你應該看看這個Java線索更深入:

因爲有其他的解決方案,例如使用鎖定對象:

或併發集合:

的是,根據您的問題,可能會更容易,而最重要的是,很經過充分測試的解決方案,可以讓您以標準方式做某些事情,從而避免所有事情在推出自定義線程代碼時可能陷入的陷阱。

希望這會有所幫助。

+0

我會避免「同步」塊,但方法是有效的(請參閱我發佈的答案)。原因是「同步」塊讓你無法控制阻塞。使用ReentrantLock可以讓你做出響應其他人鎖定的事情,而同步的塊不會。 – Matt 2012-03-31 03:47:27

+0

謝謝@Matt!有效的點 - 但是,廣泛地取決於問題。靈活性通常帶來額外的問題。 '同步'很簡單,我更喜歡它的簡單問題。在其他情況下,我使用了很多併發集合。這總是一種妥協 - 你需要更多的控制嗎?有時候不是。 – 2012-03-31 04:12:52