我正在用 Java 制作一個在線游戲,我遇到了一個特殊的問題,我試圖找到最有效的方式來發送客戶端生成物體 NPC 資料包。我當然知道如何發送它們,但我想在主游戲回圈之外進行,因為它需要回圈遍歷 NPC 的地圖(我還確保它的執行緒安全)。為此,我認為 BlockingQueue 是我最好的選擇,所以我創建了一個新執行緒,將其設定為守護行程,然后傳入一個可運行物件。然后,每當我需要發送其中一個資料包時,我都會使用 insertElement() 方法添加到佇列中。這是它的外觀。
public class NpcAsyncRunnable implements Runnable {
private final BlockingQueue<NpcObject> blockingQueue;
public NpcAsyncRunnable() {
blockingQueue = new LinkedBlockingQueue<>();
}
@Override
public void run() {
while(true) {
try {
final NpcObject obj = blockingQueue.take();
//Run my algorithm here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void insertElement(final NpcObject obj) {
blockingQueue.add(obj);
}
}
現在我的問題是這效率如何?我一直在無限回圈中運行執行緒,因為我總是希望它檢查另一個插入的元素。但是,我擔心的是如果我有太多的異步執行緒正在監聽,它會開始阻塞 CPU 嗎?我問這個是因為我知道 CPU 內核一次只能運行 1 個執行執行緒,但是使用超執行緒(AMD 有相同的東西,但它的名稱不同)它可以在需要在記憶體中搜索某些東西時在執行多個執行緒之間跳轉. 但是這個沒有讓它休眠的無限回圈是否意味著它總是會檢查佇列是否有新條目?我擔心的是我會讓 CPU 內核浪費它的所有資源,在這個執行緒上無限回圈等待另一個插入。
CPU 是否會自動分配小中斷以允許其他執行緒執行,或者我是否需要包含 sleep 陳述句,以便該執行緒使用的資源不超過所需的資源?這將使用多少 CPU 時間只是空閑?
uj5u.com熱心網友回復:
......這個無限回圈沒有讓它休眠意味著......?
blockingQueue.take() 確實會休眠,直到佇列中有要取的東西。該方法的Javadoctake說:“檢索并洗掉此佇列的頭部,如有必要,等待元素可用。”
“等待”意味著它在睡覺。任何時候你被迫寫作catch (InterruptedException...),都是因為你呼叫了某個睡眠的東西。
如果它在睡覺,它怎么知道什么時候添加了什么?它必須運行才能檢查是否已將某些內容添加到佇列中,對嗎?
不,它不需要運行。它不需要“檢查”。BlockingQueue 有效地* 用于object.wait()使執行緒“休眠”,并用于object.notify()再次喚醒它。當 Java 程式中的一個執行緒呼叫o.wait()anyObject o時,wait()呼叫不會回傳**,直到其他執行緒呼叫o.notify()相同的Object o.
wait()并且notify()是用于執行大致相同操作的特定于作業系統的呼叫的瘦包裝器。所有的魔法都發生在作業系統中。簡而言之;
- 作業系統掛起呼叫的執行緒,
o.wait()并將執行緒保存的執行背景關系添加到與物件關聯的佇列中o。 - 當其他一些執行緒呼叫
o.notify()時,作業系統將保存的執行背景關系放在佇列的頭部(如果有***),并將其移動到“準備運行”佇列。 - 一段時間后,作業系統調度程式將在“準備運行”佇列的頭部找到保存的執行緒背景關系,并將在系統的一個 CPU 上恢復背景關系。
- 那時,
o.wait()呼叫將回傳,然后等待的執行緒可以繼續處理它正在等待的任何內容(例如,NpcAsyncRunnable在您的情況下是一個物件。)
* 我不知道是否有任何特定的類implements BlockingQueue 實際使用object.wait()and ,但即使他們不使用這些方法,那么他們幾乎肯定會使用作為andobject.notify()基礎的相同作業系統呼叫。wait()notify()
** 幾乎是真的,但有一種叫做“虛假喚醒”的東西。正確使用o.wait()并且o.notify()很棘手。如果您想自己嘗試,我強烈建議您完成本教程。
o.notify()如果在呼叫它的那一刻沒有其他執行緒已經在等待,則***絕對什么都不做。不明白這一點的初學者經常會問:“為什么一直wait()沒有回來?” 它沒有回傳,因為wait()ed 的執行緒為時已晚。如果您想學習如何避免該特定錯誤,我再次敦促您完成本教程。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/513750.html
上一篇:生產者消費者Java|同步問題
