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

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

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

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

        xmemcached發布1.10 RC2,這一版本的主要改進如下:
    1、修復1.10-RC1以來發現的bug

    2、添加對flush_all協議的支持,XMemcachedClient.flushAll方法用以使memcached的緩存數據項失效,這一方法有系列重載方法

     void     flushAll()
              使cache中所有的數據項失效,如果是連接多個節點的memcached,那么所有的memcached中的數據項都將失效
     void     flushAll(long timeout)
              使cache中所有的數據項失效,如果是連接多個節點的memcached,那么所有的memcached中的數據項都將失效


     
    void     flushAll(java.net.InetSocketAddress address)
             
    使指定memcached節點的數據項失效
     void     flushAll(java.net.InetSocketAddress address, long timeout)
             
    使指定memcached節點的數據項失效

    void     flushAll(java.lang.String host)
              使指定memcached節點的數據項失效
    void     flushAll(java.lang.String host, long timeout)
              使指定memcached節點的數據項失效

    使用方法,例子:

    XMemcachedClientBuilder builder = new XMemcachedClientBuilder(
                        AddrUtil.getAddresses(
    "192.168.0.121:12000 192.168.0.121:12001"));
    XMemcachedClient client 
    = builder.build();
    // 使所有數據項失效
    client.flushAll(); 
    //使192.168.0.121:12000節點的數據項失效
    client.flushAll("192.168.0.121:12000");


    3、添加stats協議支持,用以查詢某個memcached server的統計信息:
    java.util.Map<java.lang.String,java.lang.String>     stats(java.net.InetSocketAddress address)
             
    查看特定節點的memcached server統計信息
     java.util.Map<java.lang.String,java.lang.String>     stats(java.net.InetSocketAddress address, long timeout)
              查看特定節點的memcached server統計信息
     java.util.Map
    <java.lang.String,java.lang.String>     stats(java.lang.String host)
              
    查看特定節點的memcached server統計信息
     java.util.Map<java.lang.String,java.lang.String>     stats(java.lang.String host, long timeout)
              查看特定節點的memcached server統計信息

        查詢結果以map的形式返回,map中的key-value映射與stats協議返回的一致。例子:

    //查詢192.168.0.121:12000節點的統計信息
    Map<String,String> info=xmemcachedClient.stats("192.168.0.121:12000")

    4、允許通過jmx監控XMemcachedClient的運行狀況,并調整參數等。jmx監控默認未開啟,可以通過

    -Dxmemcached.jmx.enable=true -Dxmemcached.rmi.port=7077 -Dxmemcached.rmi.name=xmemcachedServer

    的參數來啟用,那么就可以通過
    service:jmx:rmi:///jndi/rmi://[host]:7077/xmemcachedServer

    來訪問MBean。

    XMemcached提供兩個標準MBean,一個是net.rubyeye.xmemcached.impl.OptimiezerMBean,用于查看和調整性能參數;另一個是net.rubyeye.xmemcached.monitor.StatisticsHandlerMBean,用于查詢memcached客戶端的統計信息(注意跟memcached server的統計信息做區別,客戶端的統計信息可能包括了多個節點)。默認統計未開啟,可以通過

    -Dxmemcached.statistics.enable=true

    來開啟客戶端統計。更多信息請用jconsole訪問即知。

      下載地址在這里




    posted @ 2009-05-05 20:03 dennis 閱讀(1544) | 評論 (0)編輯 收藏

        以下內容純屬虛構,如有雷同純屬巧合。
        今天在偉大、光榮的xlands group里閑聊的時候,阿寶同學提到在上海被隔離的墨西哥航班乘客們被安排在一家酒店,并且房間里提供上網服務。俺不大靈光的腦袋突然靈光一閃,冒出個疑問:生物病毒可以通過比特傳播嗎?如果生物病毒可以通過比特傳播,那么互聯網將成為世界上最大的恐怖網絡。
        讓我們來認真研究這個問題,網絡上傳播只能是0和1的組成的字節,流感的DNA可以編碼成一個字節流,通過網絡傳輸到每天機器上,然后組裝成致命病毒,并通過空氣傳播感染人群。這里有幾個問題:
    1、DNA編碼成字節流,數據量會不會太大?這個可以通過挑選特定的病菌來解決,或者下面要談到的需要硬件廠商配合的方法。、

    2、怎么在用戶的機器上合成致命病菌?要知道字節序列是無生命的,一個解決辦法就是需要硬件廠商來配合,在芯片或者網卡中預先通過某種高科技的控制器存儲足量的合成病菌所需要的DNA、蛋白質等等。當網卡接收到特殊特征的字節序列(比如“你好他也好”)就啟動這個高科技控制器,吭哧吭哧地合成病毒,然后通過電腦風扇傳播到空氣中。更進一步,硬件中可以預先存放一些致命病毒(咳咳,我覺的埃博拉病毒不錯),然后在地球某個陰暗的角落(很可能是北極,變形金剛和超人都在那),一只黑手按下一個神奇的紅色按鈕,向全世界安裝了此類硬件的聯網機器發出指令釋放病毒,你說世界會怎么樣?
       
        這種可怕、恐怖、無敵的網絡恐怖主義,似乎沒有什么抵抗方法,俺這里再探討下可行的預防方法:
    1、永遠不上網
    2、機器使用一年后就淘汰,防止機器老朽病毒泄漏
    3、使用龍芯牌CPU
    4、山寨整機
    5、移居火星

       本論文版權所有,如有抄襲,板磚伺候。



    posted @ 2009-05-04 15:56 dennis 閱讀(435) | 評論 (2)編輯 收藏

    每個第一次構建分布式系統的人都可能會做出8個錯誤的對網絡的假設:
    1. The network is reliable
    2. Latency is zero
    3. Bandwidth is infinite
    4. The network is secure
    5. Topology doesn't change
    6. There is one administrator
    7. Transport cost is zero
    8. The network is homogeneous

    翻譯過來就是:
    1、網絡是穩定可靠的
    2、沒有延遲
    3、帶寬無限
    4、網絡是安全的
    5、網絡拓撲不會改變
    6、只有一個管理員
    7、傳輸成本為0
    8、網絡是均勻的,現實是各種網絡環境都有。

    更多錯誤假設:
    1、網絡IO跟磁盤IO一樣
        網絡IO比之磁盤IO更不可預測、不可靠和不可控,網絡IO包括了軟硬件兩方面的限制。
    2、你與對端能夠同步
      你無法假設對端是否關閉、接收到數據,這些通常需要你在應用協議里同步。
    3、所有的錯誤都可以被檢測到。
        很多錯誤例如對端關閉引起的讀阻塞都需要應用層來處理。

    4、資源無限可用。
    5、應用可以無限等待一個遠程服務
        任何大規模的應用都需要慎重設計超時、過期策略

    6、遠程服務總能響應及時。
    7、只有單點失敗
    8、只有一個資源分配器
    9、只有一個時間,也就是全局時間的問題。

    posted @ 2009-05-02 13:02 dennis 閱讀(1793) | 評論 (0)編輯 收藏

        最近讀薛涌的《學而時習之》,知道這本書是因為在《南方周末》上看到。閑話不說,其實這本書的精華都在那個序里,咱水平很有限,談談我的看法。序言單刀直入地表示中國文化是失敗,薛涌判斷文化是否失敗的一個標準很簡單:

        幾年前我去醫院,當我的白人醫生知道我是來自中國、而且研究中國歷史后,馬上告訴我他在大學讀過明史的課,非常景仰中國文化。我當時聽不出他到底是 出于客氣還是出于真誠,干脆直率地告訴他我的看法:從現代歷史的角度說,中國文化是個失敗的文化,至少不能說是個成功的文化。對方聽了很吃驚,馬上拿出文 化相對主義那一套和我辯論。我知道醫生惜時如金、無法在看病時開一個中國文化的討論班,就單刀直入地問他:“我愿意我和我的孩子生活在這里。你希望你或你 的后代生活在那里嗎?”他一時語塞。

        我判定中國文化成功與失敗的標準就這么簡單。我是個中國人,我的大夫是個白人。但是,我們是完 全平等的。我們中國人應該享受這些白人所享受的生活,比如有相當高的經濟收入,在憲政之下擁有自己的政治權利,等等。同生而為人,憑什么人家有這些而我們 沒有?憑什么在人家有這些而我們沒有時,還不能說我們失敗了?

        我第一次看到這個論調的時候很是震撼,乍一看似乎說的非常在理。這個標準確實簡單,一個美國人,愿意跟我調換生活嗎?先別噴,如果我的家人朋友在美國,那我肯定愿意去美國生活,因為至少那邊沒有瘦肉精,沒有城管,不用打醬油。那么這個美國人愿意嗎?那就很值的懷疑了。無論答案是肯不肯,這個遲疑本身就讓薛涌勝利了。
        這個判斷文化失敗與否的標準簡單粗暴,卻似乎直接有效。然而我卻產生個疑問,這個標準對比的當下,而當下的中國還有多少傳統文化的影子很值的懷疑;如果要對比當下,可能拿臺灣人跟美國人對比更有意義,臺灣保存的中華傳統肯定比大陸多的多,那么一個臺灣人愿意跟美國人調換生活嗎?你無法簡單地下結論了。再遠些,如果拿這個標準去對比古代,一個唐朝人愿意跟那個時期的歐洲人(咱就不跟美洲印第安人比了)調換生活嗎?這時候的你可能更偏向咱中國文化了,畢竟是盛唐時期嘛。如果從更長的時間維度看,單純按照這么個簡單粗暴的標準來衡量,中國文明似乎還相當長時間內領先于西方文明嘛。因此,還是《莫以成敗論文化/文明

    posted @ 2009-05-01 23:40 dennis 閱讀(490) | 評論 (0)編輯 收藏

    update:緊急修復一個嚴重的bug,影響多節點memcached下的余數哈希分布。jmx監控正式啟用。更多單元測試。

        XMemcached是一個基于java nio的memcached客戶端。最新發布1.10-RC1版本,這個版本其實早就完成,一直沒有環境來測試,本機測試沒有多大價值。今天做了一個初步測試,在效率上已經超越了spymemcached最新的2.3.1版本,具體的測試數據請看下面,下載地址這里,更新了wiki

       1.10-RC1的主要改進:
    1、性能優化,具體請參見wiki,在測試中已經超越了spymemcached最新的2.3.1版本
    2、重構,引入Optimiezer、XMemcachedClientBuilder等類,并引入泛型方法,使API接口更趨實用性和便捷性。1.10rc1將不兼容1.0版本,具體API請參見javadoc。可以保證的是在1.10穩定后,xmemcached在API接口不會再有大的變動。
    3、引入maven做項目構建,原來的ant構建仍然可用。
    4、bug修復,具體參見issues報告,更多測試提高健壯性。
    5、引入jmx監控,可以通過java -Dxmemcached.jmx.enable=true來啟用jmx監控,jmx功能可以統計xmemcached的各種操作次數,以及優化參數調整等,更多信息請參考javadoc和wiki

       后續計劃:
    1.10版本的正式發布
    1.11版本的開發工作,引入JMX監控。

        今天給出的是memcached存儲java原生類型的效率測試,key和value都是字符串,memcached單節點跑在局域網內的服務器上,spymemcached使用的是2.3.1版本,xmemcached使用的是1.10-RC1,兩者都是默認配置。具體圖表請看下面及相應說明。
        首先是在我本機windows xp環境(因為主要看對比,機器環境不再具體說明),連接memcached服務器所做的測試,下面是xmemcached和spymemcached的set操作效率對比,縱坐標為TPS,橫坐標為線程并發數(下同)。



        顯然,兩者的set操作效率在windows下極為接近。接下來是get操作的對比直方圖:


       
        XMemcached在get操作上保持傳統優勢,并發越大,優勢越明顯。在測試了windows下兩個客戶端的表現,繼續做linux下的測試數據,因為所用的機器是一臺8核的牛機,因此TPS非常驚人。首先是set操作的對比:
        


        不用多說,xmemcached全面占優。再看get操作的對比:



        一個奇特的現象是在200線程并發的時候,spymemcached反而超過了xmemcached,這一現象反復測試還是如此。其他并發下,xmemcached全面占優,在達到500并發時,spymemcached的get很多超時,因此數據作廢,而xmemcached由于可以設置get的操作的超時時間更長,因此仍然正常運行。
        從以上測試可以看出,1.10-RC1版本的XMemcached存儲原生類型已經在windows和linux平臺上的效率都超過了spymemcached。對于自定義對象和容器對象的存儲測試也證明xmemcached的效率已經全面超越了spymemcached。很希望有更多的測試報告,畢竟我的測試可能還是不夠客觀。



    posted @ 2009-04-28 21:50 dennis 閱讀(1731) | 評論 (2)編輯 收藏


    1、在構造函數中啟動線程
         我在很多代碼中都看到這樣的問題,在構造函數中啟動一個線程,類似這樣:
    public class A{
       
    public A(){
          
    this.x=1;
          
    this.y=2;
          
    this.thread=new MyThread();
          
    this.thread.start();
       }
       
    }
       這個會引起什么問題呢?如果有個類B繼承了類A,依據java類初始化的順序,A的構造函數一定會在B的構造函數調用前被調用,那么thread線程也將在B被完全初始化之前啟動,當thread運行時使用到了類A中的某些變量,那么就可能使用的不是你預期中的值,因為在B的構造函數中你可能賦給這些變量新的值。也就是說此時將有兩個線程在使用這些變量,而這些變量卻沒有同步。
       解決這個問題有兩個辦法:將A設置為final,不可繼承;或者提供單獨的start方法用來啟動線程,而不是放在構造函數中。

    2、不完全的同步
      
    都知道對一個變量同步的有效方式是用synchronized保護起來,synchronized可能是對象鎖,也可能是類鎖,看你是類方法還是實例方法。但是,當你將某個變量在A方法中同步,那么在變量出現的其他地方,你也需要同步,除非你允許弱可見性甚至產生錯誤值。類似這樣的代碼:
    class A{
      
    int x;
      
    public int getX(){
         
    return x;
      }
      
    public synchronized void setX(int x)
      {
         
    this.x=x;
      }
    }
        x的setter方法有同步,然而getter方法卻沒有,那么就無法保證其他線程通過getX得到的x是最新的值。事實上,這里的setX的同步是沒有必要的,因為對int的寫入是原子的,這一點JVM規范已經保證,多個同步沒有任何意義;當然,如果這里不是int,而是double或者long,那么getX和setX都將需要同步,因為double和long都是64位,寫入和讀取都是分成兩個32位來進行(這一點取決于jvm的實現,有的jvm實現可能保證對long和double的read、write是原子的),沒有保證原子性。類似上面這樣的代碼,其實都可以通過聲明變量為volatile來解決。
      
    3、在使用某個對象當鎖時,改變了對象的引用,導致同步失效。
       這也是很常見的錯誤,類似下面的代碼:
    synchronized(array[0])
    {
       ......
       array[0]=new A();
       ......
    }
       同步塊使用array[0]作為鎖,然而在同步塊中卻改變了array[0]指向的引用。分析下這個場景,第一個線程獲取了array[0]的鎖,第二個線程因為無法獲取array[0]而等待,在改變了array[0]的引用后,第三個線程獲取了新的array[0]的鎖,第一和第三兩個線程持有的鎖是不一樣的,同步互斥的目的就完全沒有達到了。這樣代碼的修改,通常是將鎖聲明為final變量或者引入業務無關的鎖對象,保證在同步塊內不會被修改引用。

    4、沒有在循環中調用wait()。

        wait和notify用于實現條件變量,你可能知道需要在同步塊中調用wait和notify,為了保證條件的改變能做到原子性和可見性。常常看見很多代碼做到了同步,卻沒有在循環中調用wait,而是使用if甚至沒有條件判斷:
    synchronized(lock)
    {
      
    if(isEmpty()
         lock.wait();
       
    }
        對條件的判斷是使用if,這會造成什么問題呢?在判斷條件之前可能調用notify或者notifyAll,那么條件已經滿足,不會等待,這沒什么問題。在條件沒有滿足,調用了wait()方法,釋放lock鎖并進入等待休眠狀態。如果線程是在正常情況下,也就是條件被改變之后被喚醒,那么沒有任何問題,條件滿足繼續執行下面的邏輯操作。問題在于線程可能被意外甚至惡意喚醒,由于沒有再次進行條件判斷,在條件沒有被滿足的情況下,線程執行了后續的操作。意外喚醒的情況,可能是調用了notifyAll,可能是有人惡意喚醒,也可能是很少情況下的自動蘇醒(稱為“偽喚醒”)。因此為了防止這種條件沒有滿足就執行后續操作的情況,需要在被喚醒后再次判斷條件,如果條件不滿足,繼續進入等待狀態,條件滿足,才進行后續操作。
    synchronized(lock)
    {
       
    while(isEmpty()
         lock.wait();
       
    }
        沒有進行條件判斷就調用wait的情況更嚴重,因為在等待之前可能notify已經被調用,那么在調用了wait之后進入等待休眠狀態后就無法保證線程蘇醒過來。

    5、同步的范圍過小或者過大。

        同步的范圍過小,可能完全沒有達到同步的目的;同步的范圍過大,可能會影響性能。同步范圍過小的一個常見例子是誤認為兩個同步的方法一起調用也是將同步的,需要記住的是Atomic+Atomic!=Atomic。
       Map map=Collections.synchronizedMap(new HashMap());
      
    if(!map.containsKey("a")){
                map.put(
    "a", value);
       }
       這是一個很典型的錯誤,map是線程安全的,containskey和put方法也是線程安全的,然而兩個線程安全的方法被組合調用就不一定是線程安全的了。因為在containsKey和put之間,可能有其他線程搶先put進了a,那么就可能覆蓋了其他線程設置的值,導致值的丟失。解決這一問題的方法就是擴大同步范圍,因為對象鎖是可重入的,因此在線程安全方法之上再同步相同的鎖對象不會有問題。
           Map map = Collections.synchronizedMap(new HashMap());
          
    synchronized (map) {
                
    if (!map.containsKey("a")) {
                    map.put(
    "a", value);
                }
            }
       注意,加大鎖的范圍,也要保證使用的是同一個鎖,不然很可能造成死鎖。 Collections.synchronizedMap(new HashMap())使用的鎖是map本身,因此沒有問題。當然,上面的情況現在更推薦使用ConcurrentHashMap,它有putIfAbsent方法來達到同樣的目的并且滿足線程安全性。

        同步范圍過大的例子也很多,比如在同步塊中new大對象,或者調用費時的IO操作(操作數據庫,webservice等)。不得不調用費時操作的時候,一定要指定超時時間,例如通過URLConnection去invoke某個URL時就要設置connect timeout和read timeout,防止鎖被獨占不釋放。
    同步范圍過大的情況下,要在保證線程安全的前提下,將不必要同步的操作從同步塊中移出。

    6、正確使用volatile
        在jdk5修正了volatile的語義后,volatile作為一種輕量級的同步策略就得到了大量的使用。volatile的嚴格定義參考jvm spec,這里只從volatile能做什么,和不能用來做什么出發做個探討。

    volatile可以用來做什么?

    1)狀態標志,模擬控制機制。常見用途如控制線程是否停止:
    private volatile boolean stopped;
    public void close(){
       stopped
    =true;
    }

    public void run(){

       
    while(!stopped){
          
    //do something
       }
       
    }
      

        前提是do something中不會有阻塞調用之類。volatile保證stopped變量的可見性,run方法中讀取stopped變量總是main memory中的最新值。

    2)安全發布,如修復DLC問題,具體參考http://www.javaeye.com/topic/260515和http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html
        private volatile IoBufferAllocator instance;
        
    public IoBufferAllocator getInsntace(){
            
    if(instance==null){
                
    synchronized (IoBufferAllocator.class) {
                    
    if(instance==null)
                        instance
    =new IoBufferAllocator();
                }
            }
            
    return instance;
        }

    3)開銷較低的讀寫鎖
    public class CheesyCounter {
        private volatile int value;

        
    public int getValue() { return value; }

        
    public synchronized int increment() {
            
    return value++;
        }
    }

    synchronized保證更新的原子性,volatile保證線程間的可見性。

    volatile不能用于做什么?
    1)不能用于做計數器
        public class CheesyCounter {
            
    private volatile int value;

            
    public int getValue() { return value; }

            
    public int increment() {
                
    return value++;
            }
        }

        因為value++其實是有三個操作組成的:讀取、修改、寫入,volatile不能保證這個序列是原子的。對value的修改操作依賴于value的最新值。解決這個問題的方法可以將increment方法同步,或者使用AtomicInteger原子類。

    2)與其他變量構成不變式
       一個典型的例子是定義一個數據范圍,需要保證約束lower<upper。
    public class NumberRange {
        
    private volatile int lower, upper;

        
    public int getLower() { return lower; }
        
    public int getUpper() { return upper; }

        
    public void setLower(int value) { 
            
    if (value > upper) 
                
    throw new IllegalArgumentException();
            lower 
    = value;
        }

        
    public void setUpper(int value) { 
            
    if (value < lower) 
                
    throw new IllegalArgumentException();
            upper 
    = value;
        }
    }

        盡管講lower和upper聲明為volatile,但是setLower和setUpper并不是線程安全方法。假設初始狀態為(0,5),同時調用setLower(4)和setUpper(3),兩個線程交叉進行,最后結果可能是(4,3),違反了約束條件。修改這個問題的辦法就是將setLower和setUpper同步:
    public class NumberRange {
        
    private volatile int lower, upper;

        
    public int getLower() { return lower; }
        
    public int getUpper() { return upper; }

        
    public synchronized void setLower(int value) { 
            
    if (value > upper) 
                
    throw new IllegalArgumentException();
            lower 
    = value;
        }

        
    public synchronized void setUpper(int value) { 
            
    if (value < lower) 
                
    throw new IllegalArgumentException();
            upper 
    = value;
        }
    }

     

    posted @ 2009-04-25 12:21 dennis 閱讀(3202) | 評論 (2)編輯 收藏

    1、散列表要解決的一個問題就是散列值的沖突問題,通常是兩種方法:鏈表法和開放地址法。鏈表法就是將相同hash值的對象組織成一個鏈表放在hash值對應的槽位;開放地址法是通過一個探測算法,當某個槽位已經被占據的情況下繼續查找下一個可以使用的槽位。java.util.HashMap采用的鏈表法的方式,鏈表是單向鏈表,因此在刪除過程中要自己維持prev節點,我想不采用雙向鏈表是從節省空間考慮。一個典型的查找過程:
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
                 e 
    != null;
                 e 
    = e.next) {
                Object k;
                
    if (e.hash == hash &&
                    ((k 
    = e.key) == key || (key != null && key.equals(k))))
                    
    return e;
     }
       HashMap采用鏈表法而不是開放地址法,猜想可能的原因是從實用角度出發,對空間和時間效率做出的折中選擇。采用開放地址法,無論是線性探測或者二次探測都可能造成群集現象,而雙重散列會要求散列表的裝填程度比較低的情況下會有比較好的查找效率,容易造成空間的浪費。

    2、什么是負載因子?負載因子a定義為
         a=散列表的實際元素數目(n)/ 散列表的容量(m)

    負載因子衡量的是一個散列表的空間的使用程度,負載因子越大表示散列表的裝填程度越高,反之愈小。對于使用鏈表法的散列表來說,查找一個元素的平均時間是 O(1+a),因此如果負載因子越大,對空間的利用更充分,然而后果是查找效率的降低;如果負載因子太小,那么散列表的數據將過于稀疏,對空間造成嚴重浪費。

    回到HashMap的實現,HashMap中的loadFactor其實定義的就是該map對象允許的最大的負載因子,如果超過這個系數將重新resize。這個是通過threshold字段來判斷,看threshold的計算:
    threshold = (int)(capacity * loadFactor);

    結合上面的負載因子的定義公式可知,threshold就是在此loadFactor和capacity對應下允許的最大元素數目,超過這個數目就重新resize,以降低實際的負載因子。默認的的負載因子0.75是對空間和時間效率的一個平衡選擇。注意到的一點是resize的規模是現有 capacity的兩倍:
      if (size++ >= threshold)
                resize(
    2 * table.length);
     
    3、可能你也注意到了,java.util.HashMap對key的hash值多做了一步處理,而不是直接使用hashCode:

    static int hash(int h) {
            h 
    ^= (h >>> 20^ (h >>> 12);
            
    return h ^ (h >>> 7^ (h >>> 4);
      }

    這個處理的原因在于HashMap的容量總是采用2的p次冪,而取index(槽位)的方法是
    static int indexFor(int h, int length) {
            
    return h & (length-1);
     }

    這一運算等價于對length取模,也就是
           h % 2^p
    返回的將是h的p個最低位組成的數字,我們假設hash輸入是符合簡單一致散列,然而這一假設并不能推論出hash的p個最低位也會符合簡單一致散列,也許h的這p個最低位相同的幾率很大,那么沖突的幾率就非常大了。優秀的散列函數應該需要考慮所有的位。

    因此為了防止這些“壞”的散列函數造成效率的降低,HashMap預先對hash值做了處理以考慮到所有的位,根據注釋也可以知道。這個處理我看不懂,留待高人解釋,也許來自于某本算法書也不一定。

    4、我們知道java.util.HashMap不是線程安全的,因此如果在使用迭代器的過程中有其他線程修改了map,那么將拋出ConcurrentModificationException,這就是所謂fail-fast策略(速錯),這一策略在源碼中的實現是通過 modCount域,modCount顧名思義就是修改次數,對HashMap內容的修改都將增加這個值,那么在迭代器初始化過程中會將這個值賦給迭代器的expectedModCount,

     HashIterator() {
                expectedModCount 
    = modCount;
                
    if (size > 0) { // advance to first entry
                    Entry[] t = table;
                    
    while (index < t.length && (next = t[index++]) == null)
                        ;
                }
            }

    在迭代過程中,判斷modCount跟expectedModCount是否相等,如果不相等就表示已經有其他線程修改了map

      
    final Entry<K,V> nextEntry() {
                
    if (modCount != expectedModCount)
                    
    throw new ConcurrentModificationException();
     注意到modCount聲明為volatile,保證線程之間修改的可見性。
     




    posted @ 2009-04-15 12:33 dennis 閱讀(4385) | 評論 (0)編輯 收藏

        小毅同學最近有個煩心事,就是他的腦袋有點偏,由于長期腦袋歪向右邊睡,導致他的大腦袋右扁左高,從上往下看,極
    其不自然。這個問題讓他爺爺奶奶、爸爸媽媽很煩心,最近計劃著給他買個定型枕,三個月了,可以睡枕頭了,趁還矯正得過
    來的時候趕緊矯正,他爸爸也叮囑媽媽要讓他側睡,一個晚上仰躺,一個晚上左側睡,希望能慢慢好起來。不然以后找不到媳
    婦可能要怨死他老媽。
        小毅同學也有個非常不好的習慣,要睡覺的時候不是乖乖睡覺,而是拼命哭鬧,非要別人抱著睡。抱著睡也還罷了,還要求
    抱的人不能坐不能停,一停或坐就又開始挺直了身體不舒坦起來了,必須在屋內走來走去,看他那小臉,很喜歡別人抱著一晃一
    晃的感覺。小毅同學睡覺也是很有趣,一開始是假寐,時刻注意抱的人是否停留,偶爾張開眼瞄你一下馬上閉上,我說他這是在
    觀察敵情呢。過那么一會,眼睛不睜了,那時候你就可以停下來坐著抱了,但是這時候還不能馬上放床上,你一放床上他也會發
    覺醒過來,你不得不重復“散步”這一階段,因此最好是坐著抱他一會,等他睡熟了再放床上去。
      小毅同學剛出生到2個月的時候,基本不笑,偶爾笑也不是對著你笑,而是對著空氣笑,讓人恨的牙癢癢,他媽媽說他這是對
    花笑,“對花笑”這詞還真有點佛意在里面。現在三個月了,開始會對著你笑,不過有個問題,他很少對著抱他的人笑,反而不
    抱他的人逗他一下就咧開了小嘴笑嘻嘻。小毅同學的哭也很有趣,頭兩個月的哭是真哭,那種臉紅脖子粗、眼淚豆大豆大往下掉
    的哭,現在哭呢,就是把眼睛咪上,“扮”出一副委屈樣,嘴里哼著我稱之為咕嚕咕嚕語的聲音,可憐兮兮地看著你,等著你抱
    他;你要是不抱,他立馬“加大音量”,此時他爺爺奶奶就撐不住了,趕緊把他抱起來,如果是我,繼續不抱的話,他馬上開始
    掉眼淚了,此時才是“真哭”呀。


    posted @ 2009-03-27 09:11 dennis 閱讀(2746) | 評論 (2)編輯 收藏

         摘要:     受javaeye上的《Ruby中文編程》啟發,帖子中有人提到如果if這樣的關鍵字都可以定義成中文,那就是真正的中文編程。那時我就想到,這個其實要在scheme中實現是多么簡單,將sicp書中的解釋器稍微修改下就可以了,只要修改解析的部分即可。解釋器的完整代碼放后面,我們先看看有趣的例子: Code highlighting produced by A...  閱讀全文

    posted @ 2009-03-20 23:27 dennis 閱讀(3118) | 評論 (8)編輯 收藏

    本圖不針對任何網站和個人,僅僅是因為很離譜。





    posted @ 2009-03-19 19:04 dennis 閱讀(1371) | 評論 (3)編輯 收藏

    僅列出標題
    共56頁: First 上一頁 17 18 19 20 21 22 23 24 25 下一頁 Last 
    主站蜘蛛池模板: 久久亚洲春色中文字幕久久久 | 亚洲av片在线观看| 精品无码免费专区毛片| 久久久久亚洲AV成人无码网站 | 亚洲精品电影在线| 57pao国产成视频免费播放| 亚洲国产国产综合一区首页| 久久久久国产精品免费网站| 久久亚洲精品中文字幕| 在线视频免费观看爽爽爽| 亚洲人成77777在线播放网站不卡 亚洲人成77777在线观看网 | 亚洲一卡2卡3卡4卡国产网站| 国产在线jyzzjyzz免费麻豆 | 黄色片网站在线免费观看| 亚洲国产高清精品线久久| 两性色午夜视频免费网| 亚洲高清在线视频| 一本岛高清v不卡免费一三区| 亚洲人成电影网站色| 亚洲一区二区视频在线观看| 国产精成人品日日拍夜夜免费| 亚洲国产美女视频| 免费无遮挡无码视频网站| 久久www免费人成精品香蕉| 久久久无码精品亚洲日韩蜜桃| 国产卡二卡三卡四卡免费网址| 亚洲经典千人经典日产| 亚洲尤码不卡AV麻豆| 天天影院成人免费观看| 理论秋霞在线看免费| 亚洲AV人无码激艳猛片| 国内自产拍自a免费毛片| 国产成人1024精品免费| 亚洲精品在线播放视频| www.91亚洲| 67pao强力打造高清免费| 黄色免费在线观看网址| 亚洲综合亚洲国产尤物| 大胆亚洲人体视频| 日本免费xxxx色视频| 一级特黄aaa大片免费看|