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

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

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

    狂奔 lion

    自強不息

    2010年6月29日

    淺談Java中的同步的方法和原理

    Java的內存模型中Thread會附有自己的堆棧,寄存器,必要時需要和主存即heap之間同步。
    可以使用Synchornized關鍵字和Concurrent包中的Lock可以保證線程互斥和可見性。

    互斥性體現在類鎖或者對象鎖上,每個對象自身都包含一個監視器,該監視器是一個每次只能被一個線程所獲取進入的臨界區,可以通過wait和notify來退出和準入臨界區。可以看出這是一個生產者-消費者的模型。而Concurrent包中的Lock為了能夠獲得更好的性能和更好的擴展性,以及不依賴于關鍵字的可讀代碼,自己實現了這樣一個生產消費隊列,也就是AbstractQueuedSynchronizer,被稱為AQS的機制。每個Lock都內置了一個AbstractQueuedSynchronizer。需要說明的是AbstractQueuedSynchronizer內部實現采用了CAS機制,通過getState, setState, compareAndSetState訪問控制一個32bit int的形式進行互斥。

    那么可見性是如何保證的呢?

    對于關鍵字的同步機制,其實可見性就是線程和主存之間的同步時機問題。共有4個時間點需要注意:
    1 獲取或釋放類鎖/對象鎖的時候。Thread保證reload/flush全部變更
    2 volatile就是flush on write或者reload on read
    3 當線程首次訪問共享變量時,可以得到最新的結果。
    題外:所以在構造方法中公布this時很危險的。簡單的說,就是構造時不逃脫任何變量,不開啟新的線程,只做封裝。關于安全構造,請參考
    http://www.ibm.com/developerworks/cn/java/j-jtp0618/#resources
    4 線程結束時,所有變更會寫回主存

    關于Concurrent Lock如何實現可見性的問題,Doug Lea大俠,只在他的論文中提到,按照JSR133,Unsafe在getState, setState, compareAndSetState時保證了線程的變量的可見性,不需要額外的volatile支持,至于具體這些native做了哪些magic就不得而知了,總之,最后的contract就是保證lock區間的共享變量可見性。開發團隊被逼急了就這樣回答:
    There seems to be a real reluctance to explain the dirty details. I think the question was definitely understood on the concurrent interest thread, and the answer is that synchronized and concurrent locking are intended to be interchangable in terms of memory semantics when implemented correctly. The answer to matfud's question seems to be "trust us.”

    不過這個地方的確是開發團隊給我們用戶迷惑的地方,在同樣應用了CAS機制的Atomic類中,都內嵌了volatile變量,但是再lock塊中,他告訴我們可以保證可見性。

    感興趣的同學可以下面的兩個thread和Doug Lea的thesis:
    http://altair.cs.oswego.edu/pipermail/concurrency-interest/2005-June/001587.html
    http://forums.sun.com/thread.jspa?threadID=631014&start=15&tstart=0
    http://gee.cs.oswego.edu/dl/papers/aqs.pdf

    posted @ 2010-07-09 19:49 楊一 閱讀(1859) | 評論 (0)編輯 收藏

    commons-net FTPClient API存取設計

    文件系統無非就是文件的存取和組織結構。
    訪問一個文件系統的API也應該是寫,讀,定位方法(Pathname?/URI?)

    FTPClient針對文件的保存和獲取各提供了兩個方法,分別是:

    public boolean storeFile(String remote, InputStream local)
    public OutputStream storeFileStream(String remote)

    public boolean retrieveFile(String remote, OutputStream local)
    public InputStream retrieveFileStream(String remote)

     

    兩個方法貌似相同,實際不同,返回流的那個因為不能馬上處理流,所以需要用戶手工調用completePendingCommand,而另一個傳遞流進去的則不需要。可能有同學已經遇到過這個問題了,讀寫第一個文件時總是正確的,當相同API讀寫第二個文件時,block住了。這是因為FTPClient要求在進行流操作之后執行completePendingCommand,以確保流處理完畢,因為流處理不是即時的,所以也沒有辦法不手工調用completePendingCommand。問題是開發者把不返回流的方法末尾加上了completePendingCommand,如果不看代碼可能根本不知道。
    文檔上說:

         * There are a few FTPClient methods that do not complete the
         
    * entire sequence of FTP commands to complete a transaction.  These
         
    * commands require some action by the programmer after the reception
         
    * of a positive intermediate command.  After the programmer's code
         * completes its actions, it must call this method to receive
         
    * the completion reply from the server and verify the success of the
         
    * entire transaction.


    但是這樣仍然還是讓人有點困惑,為什么都是存儲/讀取的方法,有時候要調用completePendingCommand,有時候不調用?更嚴重的問題是completePendingCommand調用了getReply,如果一個命令通過socket stream傳了過去但是沒有getReply,即沒有completePendingCommand,那么下次發命令時,將會受到本次返回碼的干擾,得到無效的響應。而如果在completePendingCommand之后又進行了一次無辜的completePendingCommand,那么因為FTP Server上沒有Reply了,就會block。所以completePendingCommand并不是可以隨意添加的。

    現在出現了兩個問題:
    1 completePendingCommand很容易多出來或遺漏
    2 顯式調用completePendingCommand暴露了底層實現,給用戶帶來不便,用戶只想要InputStream或者OutputStream

    為了解決這個問題,可以對InputStream進行擴展,建立一個ReplyOnCloseInputStream,如下:

    private static ReplyOnCloseInputStream extends InputStream{
      
    //
      public ReplyOnCloseInputStream(InputStream is, FTPClient c){
        
    //
      }

      
    //
      @override
      
    public void close(){
        
    if(c.completePendingCommand){
          is.close();
        }
    else{
          
    //throw Exception
        }

      }

    }
     
    //
    return new ReplyOnCloseInputStream(is, client);


    這樣封裝之后,FTPClient的用戶只需要正常在處理完流之后關閉即可,而不必暴露實現細節。保存文件也可以用相同的方法封裝OutputStream。

    posted @ 2010-07-07 23:08 楊一 閱讀(3464) | 評論 (1)編輯 收藏

    關于ThreadLocal的內存泄露

    ThreadLocal是一種confinement,confinement和local及immutable都是線程安全的(如果JVM可信的話)。因為對每個線程和value之間存在hash表,而線程數量未知,從表象來看ThreadLocal會存在內存泄露,讀了代碼,發現實際上也可能會內存泄露。

    事實上每個Thread實例都具備一個ThreadLocal的map,以ThreadLocal Instance為key,以綁定的Object為Value。而這個map不是普通的map,它是在ThreadLocal中定義的,它和普通map的最大區別就是它的Entry是針對ThreadLocal弱引用的,即當外部ThreadLocal引用為空時,map就可以把ThreadLocal交給GC回收,從而得到一個null的key。

    這個threadlocal內部的map在Thread實例內部維護了ThreadLocal Instance和bind value之間的關系,這個map有threshold,當超過threshold時,map會首先檢查內部的ThreadLocal(前文說過,map是弱引用可以釋放)是否為null,如果存在null,那么釋放引用給gc,這樣保留了位置給新的線程。如果不存在slate threadlocal,那么double threshold。除此之外,還有兩個機會釋放掉已經廢棄的threadlocal占用的內存,一是當hash算法得到的table index剛好是一個null key的threadlocal時,直接用新的threadlocal替換掉已經廢棄的。另外每次在map中新建一個entry時(即沒有和用過的或未清理的entry命中時),會調用cleanSomeSlots來遍歷清理空間。此外,當Thread本身銷毀時,這個map也一定被銷毀了(map在Thread之內),這樣內部所有綁定到該線程的ThreadLocal的Object Value因為沒有引用繼續保持,所以被銷毀。

    從上可以看出Java已經充分考慮了時間和空間的權衡,但是因為置為null的threadlocal對應的Object Value無法及時回收。map只有到達threshold時或添加entry時才做檢查,不似gc是定時檢查,不過我們可以手工輪詢檢查,顯式調用map的remove方法,及時的清理廢棄的threadlocal內存。需要說明的是,只要不往不用的threadlocal中放入大量數據,問題不大,畢竟還有回收的機制。

    綜上,廢棄threadlocal占用的內存會在3中情況下清理:
    1 thread結束,那么與之相關的threadlocal value會被清理
    2 GC后,thread.threadlocals(map) threshold超過最大值時,會清理
    3 GC后,thread.threadlocals(map) 添加新的Entry時,hash算法沒有命中既有Entry時,會清理

    那么何時會“內存泄露”?當Thread長時間不結束,存在大量廢棄的ThreadLocal,而又不再添加新的ThreadLocal(或新添加的ThreadLocal恰好和一個廢棄ThreadLocal在map中命中)時。

    posted @ 2010-07-02 18:27 楊一 閱讀(2281) | 評論 (2)編輯 收藏

    關于軟件文檔,我的看法

    文檔應該包括兩大部分,一部分是清晰的代碼結構和注釋,比如Concurrent API就是這樣,還有一部分是文字文檔,包括三個小部分:一是開發文檔,應該講架構和功能;二是索引文檔,詳細介紹功能和參數,三是用戶文檔,包括安裝和使用說明

    文檔最困難的莫過于版本的一致性,當軟件升級后,一些obsolete的內容和新的feature很難同步。要是架構發生了變化,那就更困難了。一般document team都不是太精于技術,所以也會產生一些問題。

    只能說任何事物永遠都有改進的空間,但是同樣也永遠沒有達到完美的程度

    posted @ 2010-06-29 18:26 楊一 閱讀(320) | 評論 (0)編輯 收藏

    <2010年6月>
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

    導航

    公告

    本人在blogjava上發表的文章及隨筆除特別聲明外均為原創或翻譯,作品受知識產權法保護并被授權遵從 知識分享協議:署名-非商業性使用-相同方式共享 歡迎轉載,請在轉載時注明作者姓名(楊一)及出處(m.tkk7.com/yangyi)
    /////////////////////////////////////////
    我的訪問者

    常用鏈接

    留言簿(5)

    隨筆分類(55)

    隨筆檔案(55)

    相冊

    Java

    其他技術

    生活

    最新隨筆

    搜索

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    自強不息


    用心 - 珍惜時間,勇于創造
    主站蜘蛛池模板: 99免费视频观看| 国产免费一区二区三区不卡 | 成年大片免费视频播放一级| 日本牲交大片免费观看| 国产成人精品久久亚洲高清不卡 | 亚洲熟妇无码久久精品| 国产电影午夜成年免费视频| 亚洲色图校园春色| 99在线精品视频观看免费| 亚洲av无码电影网| 日韩免费电影在线观看| 特级aaaaaaaaa毛片免费视频| mm1313亚洲国产精品美女| 无码国模国产在线观看免费| 春暖花开亚洲性无区一区二区| 亚洲av无码成人精品区在线播放 | 69视频在线观看免费| 亚洲区视频在线观看| 女人与禽交视频免费看| 四虎国产精品永免费| 亚洲av无码潮喷在线观看| 特级做A爰片毛片免费69| 野花视频在线官网免费1| 亚洲精品国产字幕久久不卡| 57pao国产成永久免费视频| 亚洲一卡2卡3卡4卡5卡6卡| 亚洲国产激情一区二区三区| 久久久久国产精品免费网站| 亚洲kkk4444在线观看| 亚洲人成影院在线观看| 69影院毛片免费观看视频在线| 亚洲精品无码久久久久秋霞| 久久精品国产亚洲精品| h视频在线观看免费网站| 亚洲性日韩精品国产一区二区| 免费看男人j放进女人j免费看| 亚洲精品综合在线影院| 亚洲国产综合久久天堂| 久久午夜夜伦鲁鲁片免费无码影视| 国产成人精品久久亚洲高清不卡| 亚洲AV无码第一区二区三区|