<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    The important thing in life is to have a great aim , and the determination

    常用鏈接

    統計

    IT技術鏈接

    保險相關

    友情鏈接

    基金知識

    生活相關

    最新評論

    雙緩沖隊列

    提出問題:為啥要有雙緩沖隊列?
        引用09年9月《程序員》上的一句話:雙緩沖隊列就是沖著同步/互斥的開銷來的。我們知道,在多個線程并發訪問同一個資源的時候,需要特別注意線程的同步問題。稍稍不注意,哦活,程序結果不正確了。最經典的就是“銀行取錢”的例子,想想,都跟現金掛上鉤了,看來這真不容忽視。
        今天我們要談的不是如何去給資源加鎖解鎖來解決同步問題,今天的重點在于,如何將線程同步的開銷降低到我們力所能及的程度。如果你覺得,你可以通過增加硬件資源來彌補程序開銷,那么,你將不可能成為一個優秀的程序員。
        進入正題,先引入一個例子,兩個實體:一個是玩具工廠,它的工作就是不停地生產玩具;另外一個實體就是小孩,它的工作就是不停地從工廠拿玩具。小孩不可能直接到工廠去“拿”玩具吧?呵呵,媽媽是絕對不會放心的。所以,我們有一個“搬運工”,搬運工自然要具備“存放”的功能,不然他怎么將玩具帶給小孩呢,是吧。所以,我們先將搬運工定義為一個List,用來存放工廠生產出來的玩具。
    代碼如下
    玩具類,定義一個玩具實體
    public class Toy {
        private String name;

        public String getName() {
            return name;
        }
    public void setName(String name) {
            this.name = name;
        }
    }

    接下來是玩具工廠,它得“不停地”生產,所以,把它設計成一個線程類

    玩具工廠,將玩具對象,放到list中
    public class Factory extends Thread{
       

        public void run(){
            while(true){
           
            Toy t = new Toy ();
           
            t.setName("玩具");
            synchronized (Tools.lT){
                Tools.lT.add(t);
    }
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
           
             }
        }
    }
    注意到,在上面這段代碼當中,必須得用synchronized (Tools.lT)將Tools.lT給加鎖。不然會出現線程同步問題(開銷就在這里)。

    再接下來,看看小孩是怎么“玩”玩具的:
    小孩類,從list中取出玩具對象
    public class Kid extends Thread {
        long time1 = System.currentTimeMillis();
        int count = 0;
        public void run() {
            while(true){
           
                synchronized(Tools.lT){
                    if(Tools.lT.size()!=0)
                Tools.lT.remove(0);
                }
                count++;
                if(count==100000){
                    javax.swing.JOptionPane.showMessageDialog(null, "用時間: "+(System.currentTimeMillis()-time1));
                    System.exit(0);
                }
           
            }
            }
    }
    當list不為空的時候,將list中的玩具對象,一個一個取出來,玩完!這個小孩可真夠厲害的,呵呵。可以想象為,該類的工作就是不停地向list中取出玩具對象。OK,再來編寫方法,如下

    主方法
    public class MainTest {

        /**
         * @param args
         */
        public static void main(String[] args) {
            Factory f = new Factory();
            f.start();
            Kid k = new Kid();
            k.start();
           
        }
    }

    最后是Tools類,他里面有個靜態的List對象:
    Tools類
    public class Tools {
        public static List<Toy>lT = new ArrayList<Toy>(10000);
    }

    這樣,我們運行一下主方法,看看我們這位“天才”玩完100000個玩具,得花銷多少的時間。

     

     


    好,31毫秒。


        這是我們的第一種解決方法,下面再來看第二種解決方法:
    其實我們在Factory類和Kid類中都進行了同步處理,這樣一來,浪費了很多時間,到底是不是這樣的呢?我們可不可以直接用一個不用處理線程同步的容器來放Toy類對象呢?這樣以來是不是就可以節省很多開銷了?這個想法是有道理的,但是,事實是不是這樣的呢?馬上實踐!

    代碼就不具體貼出來了,只是我們在Tools類中用到的是一個如下的對象
    Public static LinkedBlockingQueue<Toy> lT= new LinkedBlockingQueue<Toy>(1000);

    對,阻塞隊列,這樣我們就只管往里面取,從里面拿了,不用自己考慮同步問題,Factory類和Kid類中也不同特意去加關鍵字進行同步了。
    那么這種方案的結果是多少呢?同樣是100000個玩具,看結果
      

     

     

     


    哦哦,變成16毫秒了,著實提高了不少效果呢。看來,在處理同步的時候擠時間,是有發展空間的,呵呵。

    等等,有人要發話了,你在這磨嘰了半天,還是沒有說什么是雙緩沖啊,對!有了前面的兩種方案,我們再來看看“雙緩沖隊列”。

    所謂雙緩沖隊列,自然起碼要有兩個隊列吧,呵呵,在這個例子中,我們可以設計兩個List來存放工廠生產出來的玩具對象。
    下面分析一下:
    兩個List,一個用來存,一個用來取。有點迷糊?就是有一個listP從工廠那里得到玩具對象,另外一個listT就專門把它得到的玩具對象送去給 Kid類處理。當listT變成空的了以后,再將listP中在這段時間內取到的所有玩具對象放到listT中,好,這完了之后,他們兩個就又各自干各自的去了:listP再去取,listT再去送。這樣是不是就減少了很多次的線程同步呢?至少,在它們交換之前,listP是完全被工廠類線程占有,listT是完全被Kid類線程占有的,不用處理同步。只有在listT放完了,沒得給了,再去跟ListP換過來,這個時候就要處理同步了。

    跟實際聯系一下,有兩個搬運工A,B,A在工廠,專門從工廠取玩具;B在小孩子身邊,專門送玩具給小孩玩。當B身上沒有玩具了,自然要回A那里,把A身上的玩具全部拿過來,再來送給小孩玩。在A還有玩具的時候,A和B是在各自的線程里被處理的,即A在拿,B在給。不用擔心同步問題。
    這樣以來,處理同步問題的次數是不是大大減少了呢?沒錯,就是這樣的。那么怎么跟代碼結合呢?
    我們要設計一個監視線程,監視listP是不是空了,要是空了,把它同步起來,把listT也同步起來,讓他們交換。完了就各自干各自的了。
    我們來看看這個監視類:

    public class DoubleBufferList {

        private List<Object> lP;
        private List<Object> lT;
        private int gap;

        /**
         * 構造方法
         *
         * @param lP
         *            用來存放對象的隊列
         * @param lT
         *            用來取對象的隊列
         * @param gap
         *            交換的間隔
         */
        public DoubleBufferList(List lP, List lT, int gap) {
            this.lP = lP;
            this.lT = lT;
            this.gap = gap;
        }

        public void check() {
            Runnable runner = new Runnable() {
                public void run() {
                    while (true) {
                        if (lT.size() == 0) {
                            synchronized (lT) {
                                synchronized (lP) {
                                    lT.addAll(lP);
                                }
                                lP.clear();
                            }
                        }
                        try {
                            Thread.sleep(gap);

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            Thread thread = new Thread(runner);
            thread.start();
        }

    }


    這個類中的線程方法就是用來交換的,目的就是為了減少處理同步的次數。這種方案中,Facotry類和Kid類跟前面單個List的情況差不多,就不再給出了。只是有一點要注意,Facory類中將玩具對象是放到了lP中,而Kid類中,也只是從lT中去取對象。看看Tools類中,多了一個變量:
    Tools類,聲明兩個隊列
        public static List<Toy>lT = new ArrayList<Toy>(10000);
        public static List<Toy>lP = new ArrayList<Toy>(10000);

    同樣是讓我們的“天才”玩完100000個玩具,來看看運行需要的時間:

     

     

     


     
    哈哈,似乎跟我們上面的第二種方案,單阻塞隊列,沒有太大的差異。怎么解釋呢?
    不用著急,來,我將額定的玩具量后多加個“0”,讓他玩完1000000個!改一下單阻塞隊列方案的輸出結果,給他們一個標記。再來看看結果:

     
    效果出來了吧,我們再加大量,讓他們同時處理10000000個玩具對象: 

     

     

     

    充分說明,使用雙緩沖隊列,比單緩沖阻塞隊列的效果要好,更別說單緩沖隊列了。

    總結:
    從上面的分析,我們可以得知,在處理線程同步的時候,是要花費我們的時間的,雖然在有些時候,這樣的花費是我們可以接受的,但是在很多情況下,如果我們能注意到這樣的浪費,并且及時地完善我們的程序,這樣可以更大限度地提高我們程序的運行效率。尤其是在大的程序里面,這樣的效果體現得更明顯。而往往越大的系統,對性能的要求也就越高。

    posted on 2011-03-17 16:08 鴻雁 閱讀(1253) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     
    主站蜘蛛池模板: 中文字幕专区在线亚洲| 四虎免费久久影院| 久久久久亚洲Av无码专| baoyu116.永久免费视频| 亚洲色一色噜一噜噜噜| 国产久爱免费精品视频| 老司机亚洲精品影视www| 国内永久免费crm系统z在线| 亚洲熟女少妇一区二区| 波多野结衣免费一区视频| 亚洲国产精品VA在线看黑人| 99热在线观看免费| 亚洲国产成人久久| 嫩草影院在线免费观看| 美女免费视频一区二区| 怡红院亚洲怡红院首页| 午夜影院免费观看| 亚洲精品中文字幕无码AV| AV片在线观看免费| 亚洲成a人无码亚洲成www牛牛| 免费日本黄色网址| 成人A毛片免费观看网站| 亚洲一区中文字幕久久| 中文字幕无码不卡免费视频| 苍井空亚洲精品AA片在线播放| 大胆亚洲人体视频| 免费成人在线视频观看| 亚洲成人高清在线观看| 国产精品免费看久久久久| 国产精品免费在线播放| 亚洲三级电影网站| 特级淫片国产免费高清视频| 久久免费99精品国产自在现线 | 丝袜熟女国偷自产中文字幕亚洲| 久久er国产精品免费观看2| 亚洲一区精彩视频| 亚洲人成人无码网www国产| 久久国产高潮流白浆免费观看 | 亚洲H在线播放在线观看H| 国产免费观看网站| 久久不见久久见免费视频7|