并發(fā)編程(四):阻塞隊列

一避诽、什么是阻塞隊列

1.1 簡介

阻塞隊列(BlockingQueue)是用于進程間通信或同一進程內(nèi)的線程間通信的組件盆繁。它的工作原理是當隊列是空的時虚倒,線程試圖從隊列中獲取元素的操作將會被阻塞园爷,或者當隊列是滿時浴骂,線程往隊列里添加元素的操作會被阻塞钱磅。阻塞隊列最常用于生產(chǎn)消費模式中梦裂,生產(chǎn)者是往隊列里添加元素的線程,消費者是從隊列里拿元素的線程盖淡。

1.2 常用操作方法

最近在看方騰飛的《Java并發(fā)編程藝術》書籍年柠,書中作者對阻塞隊列常用的四種處理方法歸納的非常清晰。四種處理方法如下:

處理方式 拋出異常 返回特殊值 一直阻塞 超時退出
插入方法 add(e) offer(e) put(e) offer(e,time,unit)
移除方法 remove() poll() take() poll(time,unit)
檢查方法 element() peek() 不可用 不可用
  • 拋出異常:是指當阻塞隊列滿時候褪迟,再往隊列里插入元素冗恨,會拋出IllegalStateException(“Queue full”)異常。當隊列為空時味赃,從隊列里獲取元素時會拋出NoSuchElementException異常 掀抹。
  • 返回特殊值:插入方法會返回是否成功,成功則返回true心俗。移除方法傲武,則是從隊列里拿出一個元素,如果沒有則返回null
  • 一直阻塞:當阻塞隊列滿時城榛,如果生產(chǎn)者線程往隊列里put元素揪利,隊列會一直阻塞生產(chǎn)者線程,直到拿到數(shù)據(jù)吠谢,或者響應中斷退出土童。當隊列空時,消費者線程試圖從隊列里take元素工坊,隊列也會阻塞消費者線程献汗,直到隊列可用。
  • 超時退出:當阻塞隊列滿時王污,隊列會阻塞生產(chǎn)者線程一段時間罢吃,如果超過一定的時間,生產(chǎn)者線程就會退出昭齐。

1.3 Java里的阻塞隊列

JDK7提供了7個阻塞隊列尿招。分別是

  • ArrayBlockingQueue :一個由數(shù)組結(jié)構(gòu)組成的有界阻塞隊列。
  • LinkedBlockingQueue :一個由鏈表結(jié)構(gòu)組成的有界阻塞隊列阱驾。
  • PriorityBlockingQueue :一個支持優(yōu)先級排序的無界阻塞隊列就谜。
  • DelayQueue:一個使用優(yōu)先級隊列實現(xiàn)的無界阻塞隊列。
  • SynchronousQueue:一個不存儲元素的阻塞隊列里覆。
  • LinkedTransferQueue:一個由鏈表結(jié)構(gòu)組成的無界阻塞隊列丧荐。
  • LinkedBlockingDeque:一個由鏈表結(jié)構(gòu)組成的雙向阻塞隊列。

1.4 為什么用隊列喧枷?

image

如上圖它是一種線性列表虹统,以FIFO(先進先出)的順序訪問。由于隊列是線性列表隧甚,在查找元素時需要一個一個遍歷车荔,效率非常低,所以不適合做查詢操作戚扳,那么它的優(yōu)點在哪忧便?優(yōu)點在于他們每一個節(jié)點是串聯(lián)的,在移動或刪除元素時帽借,只需要修改節(jié)點指向的元素珠增,而在數(shù)組中當你刪除其中一個元素時,需要把該元素后邊所有元素位置重新排列宜雀,這就使得隊列在插入和刪除上效率要比數(shù)組中高切平,詳細如下圖所示。那么在游戲服務器開發(fā)中它的主要應用場景有哪一些辐董?比如:頻道聊天悴品,AOI、郵件群發(fā)等等简烘。

image

頻道聊天

玩家A在頻道發(fā)送消息-----> 服務器------->該頻道玩家看到了這個玩家A發(fā)的消息

AOI

玩家A在場景B對NPC使用技能-----> 服務器------->該場景B附近的玩家能看到玩家A在使用技能

使用消息隊列的十大理由:http://www.oschina.net/translate/top-10-uses-for-message-queue?cmp

1.5 代碼示例(頻道聊天)

package com.game.lll.queue;  
  
import java.util.concurrent.BlockingQueue;  
import java.util.concurrent.LinkedBlockingQueue;  
  
  
public class LinkedBlockingQueueTest{  
  
    public static final int WORLD = 0;//世界頻道      
    public static final int AREA = 1;//區(qū)域頻道  
    public static final int SYSTEM = 2;//系統(tǒng)消息  
  
    public static final String[] NAME = {"世界","區(qū)域","系統(tǒng)"};  
  
    protected BlockingQueue<ChatMessage> messages = new LinkedBlockingQueue<ChatMessage>();  
  
    private Producer producer1 = new Producer("小毛驢");  
    private Producer producer2 = new Producer("小兔子");  
    private Producer producer3 = new Producer("小貓咪");  
    private Consumer consumer = new Consumer();  
      
    public static void main(String[] args) {  
        LinkedBlockingQueueTest queueTest = new LinkedBlockingQueueTest();  
        queueTest.consumer.start();;  
          
        for(int i=0;i<10;i++){    
            new Thread(){    
                public void run() {    
                    queueTest.producer1.addChatMessage("大家好苔严!", WORLD);  
                    queueTest.producer2.addChatMessage("大家好!", AREA);  
                    queueTest.producer3.addChatMessage("大家好孤澎!", SYSTEM);  
                };    
            }.start();    
        }    
  
        while(Thread.activeCount()>1)  //保證前面的線程都執(zhí)行完    
            Thread.yield();    
    }  
  
  
    public class Producer  
    {  
        protected String name;  
        public Producer(String name) {  
            this.name = name;  
        }  
        public void addChatMessage(String message,int channel) {  
            messages.add(new ChatMessage(name, message, channel));  
        }  
    }  
  
    public class Consumer extends Thread{  
  
        @Override  
        public void run() {  
            while (true) {  
                try {  
                    ChatMessage message = messages.take();  
                    switch (message.channel) {  
                    case WORLD:  
                        //  
                        break;  
                    case AREA:  
                        //  
                        break;  
                    case SYSTEM:  
                        //  
                        break;  
  
                    default:  
                        break;  
                    }  
                    System.out.println("【"+NAME[message.channel]+"】"+message.name+":"+message.message);  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }  
  
        }  
  
    }  
  
  
    public class ChatMessage  
    {  
        protected String name;  
        protected String message;  
        protected int channel;  
  
        public ChatMessage(String name,String message,int channel)  
        {  
            this.name = name;  
            this.message = message;  
            this.channel = channel;  
        }  
    }  
  
}  

控制臺:

【世界】小毛驢:大家好届氢!
【世界】小毛驢:大家好!
【區(qū)域】小兔子:大家好覆旭!
【系統(tǒng)】小貓咪:大家好退子!
【世界】小毛驢:大家好岖妄!
【區(qū)域】小兔子:大家好!
【系統(tǒng)】小貓咪:大家好寂祥!
【世界】小毛驢:大家好荐虐!
【區(qū)域】小兔子:大家好!
【系統(tǒng)】小貓咪:大家好丸凭!
【世界】小毛驢:大家好福扬!
【區(qū)域】小兔子:大家好!
【系統(tǒng)】小貓咪:大家好惜犀!
【世界】小毛驢:大家好铛碑!
【區(qū)域】小兔子:大家好!
【系統(tǒng)】小貓咪:大家好虽界!
【世界】小毛驢:大家好汽烦!
【區(qū)域】小兔子:大家好!
【系統(tǒng)】小貓咪:大家好浓恳!
【世界】小毛驢:大家好刹缝!
【區(qū)域】小兔子:大家好!
【系統(tǒng)】小貓咪:大家好颈将!
【世界】小毛驢:大家好梢夯!
【區(qū)域】小兔子:大家好!
【系統(tǒng)】小貓咪:大家好晴圾!
【區(qū)域】小兔子:大家好颂砸!
【系統(tǒng)】小貓咪:大家好!
【世界】小毛驢:大家好死姚!
【區(qū)域】小兔子:大家好人乓!
【系統(tǒng)】小貓咪:大家好!

作者:小毛驢都毒,一個Java游戲服務器開發(fā)者 原文地址:https://liulongling.github.io/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末色罚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子账劲,更是在濱河造成了極大的恐慌戳护,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瀑焦,死亡現(xiàn)場離奇詭異腌且,居然都是意外死亡,警方通過查閱死者的電腦和手機榛瓮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門铺董,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人禀晓,你說我怎么就攤上這事精续“用蹋” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵驻右,是天一觀的道長什黑。 經(jīng)常有香客問我崎淳,道長堪夭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任拣凹,我火速辦了婚禮森爽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嚣镜。我一直安慰自己爬迟,他們只是感情好,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布菊匿。 她就那樣靜靜地躺著付呕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪跌捆。 梳的紋絲不亂的頭發(fā)上徽职,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音佩厚,去河邊找鬼姆钉。 笑死,一個胖子當著我的面吹牛抄瓦,可吹牛的內(nèi)容都是我干的潮瓶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼钙姊,長吁一口氣:“原來是場噩夢啊……” “哼毯辅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起煞额,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤思恐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后立镶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體壁袄,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年媚媒,在試婚紗的時候發(fā)現(xiàn)自己被綠了嗜逻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡缭召,死狀恐怖栈顷,靈堂內(nèi)的尸體忽然破棺而出逆日,到底是詐尸還是另有隱情,我是刑警寧澤萄凤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布室抽,位于F島的核電站,受9級特大地震影響靡努,放射性物質(zhì)發(fā)生泄漏坪圾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一惑朦、第九天 我趴在偏房一處隱蔽的房頂上張望兽泄。 院中可真熱鬧,春花似錦漾月、人聲如沸病梢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜓陌。三九已至,卻和暖如春吩蔑,著一層夾襖步出監(jiān)牢的瞬間钮热,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工哥纫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留霉旗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓蛀骇,卻偏偏與公主長得像厌秒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子擅憔,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容