當前位置:
首頁 > 知識 > 編程思想之消息機制

編程思想之消息機制

(點擊

上方公眾號

,可快速關注)




來源:luoweifu ,


blog.csdn.net/luoweifu/article/details/45568411




從一個劇情開始



路遙的《平凡的世界》因為翻拍成電視劇,又再次火起來了!我們就從這裡開始吧,其小說是以這樣一個場景開頭的:




在一個半山腰縣立高中的大院壩里,在一個校園內的南牆根下,按班級排起了十幾個縱隊的年輕男女,各班的值日生正忙碌地給眾人分發飯菜…… 菜分為甲、乙、丙三等,甲菜以土豆、白菜、粉條為主,還有可人大肉片,乙菜沒有肉,丙菜只有清水煮白蘿蔔。主食也分為三等:白面饃,玉米面饃,高粱面饃,白、黃、黑分別代表了三種差別,學生們戲稱歐洲、亞洲、非洲。每個人的飯菜都是昨天登記好並付了飯票的,在這一長長的隊伍中自然以光景較好的富家子弟排在最前,光景一般的隨後,而那些家庭貧困少吃缺穿的學生只能在其他學生走後才姍姍來遲……









這一活生生的例子雖然看著有些悲涼(排隊打飯的情景相信曾經是學生的你一定經歷過,可能沒這般悲涼而已),卻像極了消息機制的原理,也許發明消息機制的靈感就是原來於這樣的生活吧!排隊的學生就是消息隊列,值日生分發飯菜就消息循環並完成消息處理,學生吃飯就類似於事件處理。




什麼是消息?




何為消息?消息就是帶有某種信息的信號,如你用滑鼠點擊一個窗口會產生滑鼠的消息,鍵盤輸入字元會產生鍵盤的消息,一個窗口大小的改變也會產生消息。


消息從何而來?根據馮·諾依曼的體系結構計算機有運算器、存儲器、控制器和輸入設備和輸出設備五大部件組成,消息主要來自輸入設備,如鍵盤、滑鼠、掃描儀等,也可來自已窗口和操作系統。


消息機制的三大要點:消息隊列、消息循環(分發)、消息處理。其結構如下:




圖 1 :消息機制原理






  • 消息隊列

    就是存放消息的一種隊列,具有先進先出的特點。每產生一個消息都會添加進消息隊列中,在Window中消息隊列是在操作系統中定義的。消息隊列就如同一群排隊打飯的少男少女,這群人中光景較好的排在前面,光景較差的排在後面,可以理解成是一種優先順序隊列!要想更多的了解隊列的相關知識,可參見隊列。



  • 消息循環

    就是通過循環(如while)不斷地從消息隊列中取得隊首的消息,並將消息分發出去。類似於上面的例子中分發飯菜值日生。



  • 消息處理

    就是在接收到消息之後根據不同的消息類型做出不同的處理。上面例子中值日生根據學生不同類型的飯票給他們不同等級的飯菜就是消息處理,學生手中的飯票就是消息所攜帶的信息。



  • 事件

    是根據接收到的消息的具體信息做出的特定的處理,放在代碼中是事件響應函數。上面的例子中學生拿到飯菜後吃飯就是具體的事件。




消息機制模擬




在這裡我們以控制台輸入信息模擬窗口、對話框接收滑鼠、鍵盤等消息,以ArrayBlockingQueue對象存放消息隊列。在控制台中輸入一個數值和一個字元串代表一個消息,輸入-1結束輸入。模擬代碼如下:





package message;


 


import java.util.Queue;


import java.util.Scanner;


import java.util.concurrent.ArrayBlockingQueue;


 


/**


 * 消息


 * @author luoweifu


 */


class Message {


    //消息類型


    public static final int KEY_MSG = 1;


    public static final int MOUSE_MSG = 2;


    public static final int SYS_MSG = 3;


 


    private Object source;  //來源


    private int type;       //類型


    private String info;    //信息


 


    public Message(Object source, int type, String info) {


        super();


        this.source = source;


        this.type = type;


        this.info = info;


    }


 


    public Object getSource() {


        return source;


    }


    public void setSource(Object source) {


        this.source = source;


    }


    public int getType() {


        return type;


    }


    public void setType(int type) {


        this.type = type;


    }


    public String getInfo() {


        return info;


    }


    public void setInfo(String info) {


        this.info = info;


    }


    public static int getKeyMsg() {


        return KEY_MSG;


    }


    public static int getMouseMsg() {


        return MOUSE_MSG;


    }


    public static int getSysMsg() {


        return SYS_MSG;


    }


}


 


interface MessageProcess {


    public void doMessage(Message msg);


}


 


/**


 * 窗口模擬類


 */


class WindowSimulator implements MessageProcess{


    private ArrayBlockingQueue msgQueue;


    public WindowSimulator(ArrayBlockingQueue msgQueue) {


        this.msgQueue = msgQueue;


    }


 


    public void GenerateMsg() {


        while(true) {


            Scanner scanner = new Scanner(System.in);


            int msgType = scanner.nextInt();


            if(msgType < 0) {           //輸入負數結束循環


                break;


            }


            String msgInfo = scanner.next();


            Message msg = new Message(this, msgType, msgInfo);


            try {


                msgQueue.put(msg);      //新消息加入到隊尾


            } catch (InterruptedException e) {


                e.printStackTrace();


            }


        }


    }


 


    @Override


    /**


     * 消息處理


     */


    public void doMessage(Message msg) {


        switch(msg.getType()) {


        case Message.KEY_MSG:


            onKeyDown(msg);


            break;


        case Message.MOUSE_MSG:


            onMouseDown(msg);


            break;


        default:


            onSysEvent(msg);


        }


    }


 


    //鍵盤事件


    public static void onKeyDown(Message msg) {


        System.out.println("鍵盤事件:");


        System.out.println("type:" + msg.getType());


        System.out.println("info:" + msg.getInfo());


    }


 


    //滑鼠事件


    public static void onMouseDown(Message msg) {


        System.out.println("滑鼠事件:");


        System.out.println("type:" + msg.getType());


        System.out.println("info:" + msg.getInfo());


    }


 


    //操作系統產生的消息


    public static void onSysEvent(Message msg) {


        System.out.println("系統事件:");


        System.out.println("type:" + msg.getType());


        System.out.println("info:" + msg.getInfo());


    }


}


 


/**


 * 消息模擬


 * @author luoweifu


 */


public class MessageSimulator {


    //消息隊列


    private static ArrayBlockingQueue<Message> messageQueue = new ArrayBlockingQueue<Message>(100);


 


    public static void main(String[] args) {


        WindowSimulator generator = new WindowSimulator(messageQueue);


        //產生消息


        generator.GenerateMsg();


 


        //消息循環


        Message msg = null;


        while((msg = messageQueue.poll()) != null) {


            ((MessageProcess) msg.getSource()).doMessage(msg);


        }


    }


}




這裡模擬用例中只有一個消息輸入源,且是一種線程阻塞的,只有輸入結束後才會進行消息的處理。真實的Windows操作系統中的消息機制會有多個消息輸入源,且消息輸入的同時也能進行消息的處理。




【關於投稿】




如果大家有原創好文投稿,請直接給公號發送留言。




① 留言格式:


【投稿】+《 文章標題》+ 文章鏈接

② 示例:


【投稿】《不要自稱是程序員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/

③ 最後請附上您的個人簡介哈~






看完本文有收穫?請轉發分享給更多人


關注「ImportNew」,提升Java技能


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 ImportNew 的精彩文章:

FutureTask 在線程池中應用和源碼解析

TAG:ImportNew |