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

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

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

    2007年3月25日

    新寫了一個(gè)Java并發(fā)程序設(shè)計(jì)教程, 用于公司內(nèi)部培訓(xùn)的,和2007年寫的那個(gè)相比,內(nèi)容更翔實(shí)一些。

    內(nèi)容列表

    1、使用線程的經(jīng)驗(yàn):設(shè)置名稱、響應(yīng)中斷、使用ThreadLocal
    2、Executor :ExecutorService和Future ☆ ☆ ☆
    3、阻塞隊(duì)列 : put和take、offer和poll、drainTo
    4、線程間的協(xié)調(diào)手段:lock、condition、wait、notify、notifyAll ☆ ☆ ☆
    5、Lock-free: atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList ☆ ☆ ☆
    6、關(guān)于鎖使用的經(jīng)驗(yàn)介紹
    7、并發(fā)流程控制手段:CountDownlatch、Barrier
    8、定時(shí)器: ScheduledExecutorService、大規(guī)模定時(shí)器TimerWheel
    9、并發(fā)三大定律:Amdahl、Gustafson、Sun-Ni
    10、神人和圖書
    11、業(yè)界發(fā)展情況: GPGPU、OpenCL
    12、復(fù)習(xí)題

    下載地址:

     http://files.cnblogs.com/jobs/Java%e5%b9%b6%e5%8f%91%e7%a8%8b%e5%ba%8f%e8%ae%be%e8%ae%a1%e6%95%99%e7%a8%8b.pdf  

     歡迎看了之后寫反饋給我。
    博客園的文章地址:

    http://www.cnblogs.com/jobs/archive/2010/07/29/1788156.html

    posted @ 2010-07-30 00:41 溫少的日志 閱讀(6401) | 評(píng)論 (12)編輯 收藏
     
    Google云計(jì)算AppEngine Java版剛剛推出來的時(shí)候,我就申請(qǐng)了該服務(wù)。該服務(wù)的申請(qǐng)需要提供手機(jī)號(hào)碼驗(yàn)證,GOOGLE很牛B,能夠發(fā)送全球的手機(jī)短信。申請(qǐng)的帳號(hào)放了很久, 前段時(shí)間學(xué)習(xí)OpenID,需要作一個(gè)范例,于是就在Google AppEngine上作,作的過程發(fā)現(xiàn)其不能使用線程,導(dǎo)致HttpClient組件無法工作,于是我修改了OpenID4Java的實(shí)現(xiàn),全部使用 URLConnection來實(shí)現(xiàn)。最終程序部署成功了,網(wǎng)址 http://cogito-study.appspot.com,歡迎大家測(cè)試使用。

    我來說一下我對(duì)Google AppEngine Java版本的使用感受吧。
    1、 Google AppEngine Java版本,具備基本功能,但是由于缺乏一些重要的功能,例如線程,沒有線程,很多庫無法使用,例如我上面提到的HttpClient不能使用。 Google提供一個(gè)類的白名單http://code.google.com/intl/zh-CN/appengine/docs/java /jrewhitelist.html,大多數(shù)需要使用的類都有,javax.xml.crypto不再其中,使得我要部署一個(gè)SAML2的實(shí)現(xiàn)時(shí)玩不 轉(zhuǎn)。
    2、Google AppEngine提供了一個(gè)DataStore,使用JDO訪問數(shù)據(jù),其查詢語言支持GQL。基本功能是具備的,但是也是存在很大的局限性,最多返回 1000行數(shù)據(jù),COUNT(*)也是最多返回1000行。這個(gè)限制使得很多應(yīng)用要跑在其上,會(huì)很麻煩。
    3、部署很簡(jiǎn)單,在Eclipse中使用Google提供的插件,輸入帳號(hào)密碼就可以部署了,太簡(jiǎn)單了。但我使用的過程中,經(jīng)常出現(xiàn)某些時(shí)段無法部署的情況,通常遇到這種情況,多嘗試幾次或者過段時(shí)間再嘗試就好了。
    4、管理界面簡(jiǎn)潔方便,功能基本完備。包括性能監(jiān)控、數(shù)據(jù)管理、日志、計(jì)費(fèi)等都有。
    總結(jié)
    Google的AppEngine Java版本已經(jīng)具備了基本功能,可以部署簡(jiǎn)單應(yīng)用了,但是由于其功能不夠完備,目前大多數(shù)應(yīng)用要部署在其上,都會(huì)要做相當(dāng)大的修改或者無法實(shí)現(xiàn)。
    posted @ 2009-09-27 20:29 溫少的日志 閱讀(1526) | 評(píng)論 (0)編輯 收藏
     
    我在Google AppEngine上部署了一個(gè)Java應(yīng)用(OpenID測(cè)試)
    http://cogito-study.appspot.com

    Google Apps不支持線程,所用到的庫openid4java需要?jiǎng)?chuàng)建線程(因?yàn)镠ttpClient),我修改了openid4java的實(shí)現(xiàn),使得其支持Google App Engine。

    部署在Google App Engine上的應(yīng)用可以應(yīng)用任何OpenID Provider登陸,包括Google、Yahoo、MSN等。

    你可以通過這個(gè)測(cè)試網(wǎng)站了解OpenID
    posted @ 2009-09-24 21:22 溫少的日志 閱讀(1658) | 評(píng)論 (1)編輯 收藏
     
    最近花了較多時(shí)間學(xué)習(xí)單點(diǎn)登陸以及相關(guān)的安全技術(shù),做一個(gè)簡(jiǎn)單的總結(jié),發(fā)表我的一些看法。拋磚引玉,希望各位朋友參與討論。

    單點(diǎn)登陸,鳥語原文為Single Sign-On,縮寫為SSO。別以為單點(diǎn)登陸是很時(shí)髦高深的技術(shù),相反單點(diǎn)登陸是很古老的技術(shù),例如1980年kerberos v4發(fā)布,一直發(fā)展至今,被Windows、Mac OS X、Linux等流行的操作系統(tǒng)所采用,是為應(yīng)用最廣泛的單點(diǎn)登陸技術(shù)。

    kerberos適用于局域網(wǎng),十分成熟。互聯(lián)網(wǎng)發(fā)展之后,多個(gè)網(wǎng)站需要統(tǒng)一認(rèn)證,業(yè)界需要適合互聯(lián)網(wǎng)的單點(diǎn)登陸技術(shù),也就是WEB SSO。2002年,微軟提出了passport服務(wù),由微軟統(tǒng)一提供帳號(hào)和認(rèn)證服務(wù),理所當(dāng)然,大家都不愿意受制于微軟,但是很認(rèn)同微軟提出WEB SSO理念,于是產(chǎn)生了Liberty Alliance,另外指定一套標(biāo)準(zhǔn),這套標(biāo)準(zhǔn)發(fā)展起來就是SAML,目前SAML的版本是SAML V2,屬于OASIS的標(biāo)準(zhǔn)。

    --------------
    SAML

    SAML,鳥語全名為Security Assertion Markup Language,彌漫著學(xué)院派的腐尸味道,縮寫十分怪異,令人望而生畏。計(jì)算機(jī)行業(yè),向來崇尚時(shí)髦,SAML這一名稱使得其較少受到大眾程序員的關(guān)注。

    SAML的標(biāo)準(zhǔn)制定者,來自SUN、BEA、IBM、RSA、AOL、Boeing等大公司,制定技術(shù)規(guī)范相當(dāng)專業(yè)有水準(zhǔn),系統(tǒng)分層合理,抽象了幾個(gè)概念把整個(gè)系統(tǒng)描述得很清楚,使用流行技術(shù)XML Schema來描述協(xié)議,使用到了XML-Sign和XML Encrypt等較為前緣XML安全技術(shù)。

    SAML的基本部分包括Protocol、Bingding、Profile、Metadata、AuthenticationContext。其中Protocol是交互消息的格式,例如AuthnRuequest/Response(認(rèn)證請(qǐng)求/響應(yīng))的消息對(duì)。Bingding是指協(xié)議所采用的傳輸方式,例如使用HTTP Redirect或HTTP POST或SOAP的方式傳輸Protocol中所定義的消息。Profile是系統(tǒng)角色間交互消息的各種場(chǎng)景,例如Web Single Sign-ON是一種Profile、Single Sign-Out也是一種Profile、身份聯(lián)邦也是一種Profile。各個(gè)參與方所提供的服務(wù)的描述信息為metadata。系統(tǒng)的認(rèn)證方法通常是千差萬別的,AuthenticationContext是SAML中定義的認(rèn)證擴(kuò)展點(diǎn),可以是最普通的User Password認(rèn)證,也可以是kerberos認(rèn)證,也可以是電信常用的RADIUS,或者是動(dòng)態(tài)密碼卡。

    SAML在Java企業(yè)應(yīng)用中,得到廣泛支持,IBM、BEA、ORACLE、SUN的Java應(yīng)用服務(wù)器都提供了SAML的支持,曾經(jīng)有人說,SAML就是如同JDBC一樣,將會(huì)是使系統(tǒng)集成的準(zhǔn)入證。SAML有很多開源實(shí)現(xiàn),包括SUN公司的Open SSO,不幸的是,這些開源實(shí)現(xiàn)都不夠好,或者相當(dāng)糟糕,如果我們需要支持SAML協(xié)議,可能需要在開源的版本上裁剪或者另行開發(fā)。

    SAML考慮了Web SSO,也考慮了傳統(tǒng)的SSO集成,包括Kerberos和LDAP的集成,其中Attributed擴(kuò)展機(jī)制以及相關(guān)規(guī)范,使得SAML擁有良好的擴(kuò)展性,很好集成傳統(tǒng)協(xié)議和支持新協(xié)議。

    SAML是一個(gè)定義良好的規(guī)范,概念清晰,分層合理,擴(kuò)展性良好,一切都很棒,但是有一點(diǎn)不好,就是曲高和寡!

    -------------
    OpenID
    有一些互聯(lián)網(wǎng)公司,擁有眾多很多帳號(hào),很牛B,例如GOOGLE、YAHOO、Facebook,希望別人的系統(tǒng)使用它們的帳號(hào)登陸。他們希望一種足夠簡(jiǎn)單的WEB SSO規(guī)范,于是選擇一種草根網(wǎng)絡(luò)協(xié)議OpenID。OpenID,名字取得好,顧名思義,一看就知道它是干嘛的。國內(nèi)也有它的Fans,例如豆瓣網(wǎng)。openID的確足夠簡(jiǎn)單,但是協(xié)議本身是不完善,可能需要一些補(bǔ)充協(xié)議才能夠滿足業(yè)務(wù)需求。例如GOOGLE采用OpenID + OAuth。目前支持OpenID有Yahoo、Google、Windows Live,還有號(hào)稱要支持OpenID的Facebook。目前Yahoo和Google宣稱對(duì)OpenID的支持,但是其實(shí)是有限制的,Yahoo的OpenID只有少數(shù)合作伙伴才能獲得其屬性,Google也只有在其Google Apps中才能獲得賬號(hào)的Attribute。用戶賬號(hào)畢竟是一個(gè)互聯(lián)網(wǎng)公司的最寶貴資源,希望他們完全分享賬號(hào)是不可能的。

    Open ID和SAML兩種規(guī)范,都將會(huì)減少系統(tǒng)間交互的成本,我們提供Open API時(shí),應(yīng)該支持其中一種或者或兩種規(guī)范。

    --------------
    OAuth

    oAuth涉及到3大塊的交互和通信。1. 用戶,2. 擁有用戶資料/資源的服務(wù)器A,3. 求資源的服務(wù)器B,。

    oAuth的典型應(yīng)用場(chǎng)景(senario)
    以前,用戶在 擁有資源 的的網(wǎng)站A有一大堆東西;現(xiàn)在用戶發(fā)現(xiàn)了一個(gè)新的網(wǎng)站B,比較好玩,但是這個(gè)新的網(wǎng)站B想調(diào)用 擁有資源的網(wǎng)站A的數(shù)據(jù)。

    用戶在 求資源的網(wǎng)站B 上,點(diǎn)擊一個(gè)URL,跳轉(zhuǎn)到 擁有 資源的網(wǎng)站A。
    擁有資源的網(wǎng)站A提示:你需要把資源分享給B網(wǎng)站嗎?Yes/No。
    用戶點(diǎn)擊 Yes,擁有資源的網(wǎng)站A 給 求資源的網(wǎng)站B 臨時(shí)/永久 開一個(gè)通道,然后 求資源的網(wǎng)站 就可以來 擁有資源的網(wǎng)站 抓取所需的信息了。
    (參考資料:http://initiative.yo2.cn/archives/633801)
    (摘抄)
    --------------

    內(nèi)部系統(tǒng)間集成使用LDAP、Kerberos,外部系統(tǒng)集成使用SAML或者OpenID + OAuth,這是一種建議的模式。

    ------------
    PAM

    人們尋找一種方案:一方面,將鑒別功能從應(yīng)用中獨(dú)立出來,單獨(dú)進(jìn)行模塊化設(shè)計(jì),實(shí)現(xiàn)和維護(hù);另一方面,為這些鑒別模塊建立標(biāo)準(zhǔn) API,以便各應(yīng)用程序能方便的使用它們提供的各種功能;同時(shí),鑒別機(jī)制對(duì)其上層用戶(包括應(yīng)用程序和最終用戶)是透明的。直到 1995 年,SUN 的研究人員提出了一種滿足以上需求的方案--插件式鑒別模塊(PAM)機(jī)制并首次在其操作系統(tǒng) Solaris 2.3 上部分實(shí)現(xiàn)。插件式鑒別模塊(PAM)機(jī)制采用模塊化設(shè)計(jì)和插件功能,使得我們可以輕易地在應(yīng)用程序中插入新的鑒別模塊或替換原先的組件,而不必對(duì)應(yīng)用程序做任何修改,從而使軟件的定制、維持和升級(jí)更加輕松--因?yàn)殍b別機(jī)制與應(yīng)用程序之間相對(duì)獨(dú)立。應(yīng)用程序可以通過 PAM API 方便的使用 PAM 提供的各種鑒別功能,而不必了解太多的底層細(xì)節(jié)。此外,PAM的易用性也較強(qiáng),主要表現(xiàn)在它對(duì)上層屏蔽了鑒別的具體細(xì)節(jié),所以用戶不必被迫學(xué)習(xí)各種各樣的鑒別方式,也不必記住多個(gè)口令;又由于它實(shí)現(xiàn)了多鑒別機(jī)制的集成問題,所以單個(gè)程序可以輕易集成多種鑒別機(jī)制如 Kerberos 鑒別機(jī)制和 Diffie - Hellman 鑒別機(jī)制等,但用戶仍可以用同一個(gè)口令登錄而感覺不到采取了各種不同鑒別方法。PAM 后來被標(biāo)準(zhǔn)化為 X/Open UNIX® 標(biāo)準(zhǔn)化流程(在 X/Open 單點(diǎn)登錄服務(wù)(XSSO)架構(gòu)中)的一部分。(摘抄)

    如果我們?cè)O(shè)計(jì)一個(gè)認(rèn)證系統(tǒng),PAM是應(yīng)該參考借鑒的。

    -------------
    JAAS
    Java Authentication Authorization Service(JAAS,Java驗(yàn)證和授權(quán)API)提供了靈活和可伸縮的機(jī)制來保證客戶端或服務(wù)器端的Java程序。Java早期的安全框架強(qiáng)調(diào)的是通過驗(yàn)證代碼的來源和作者,保護(hù)用戶避免受到下載下來的代碼的攻擊。JAAS強(qiáng)調(diào)的是通過驗(yàn)證誰在運(yùn)行代碼以及他/她的權(quán)限來保護(hù)系統(tǒng)面受用戶的攻擊。它讓你能夠?qū)⒁恍?biāo)準(zhǔn)的安全機(jī)制,例如Solaris NIS(網(wǎng)絡(luò)信息服務(wù))、Windows NT、LDAP(輕量目錄存取協(xié)議),Kerberos等通過一種通用的,可配置的方式集成到系統(tǒng)中。在客戶端使用JAAS很簡(jiǎn)單。在服務(wù)器端使用JAAS時(shí)情況要復(fù)雜一些。(摘抄)

    -------------
    Spring Security,Spring框架大名鼎鼎,Spring Security屬于SpringFramework旗下的一個(gè)子項(xiàng)目,源自acegi 1.x發(fā)展起來。很多人項(xiàng)目應(yīng)用了spring security,但我個(gè)人看來,spring security絕對(duì)不算是一個(gè)設(shè)計(jì)良好的安全框架。其設(shè)計(jì)感覺就是一個(gè)小項(xiàng)目的安全認(rèn)證實(shí)踐罷了。

    -------------
    CAS
    應(yīng)用最廣的開源單點(diǎn)登陸實(shí)現(xiàn)了,其實(shí)現(xiàn)模仿Kerberos的一些概念,例如KDC、TGS等等,都是來自于Kerberos。CAS對(duì)SAML和OpenID協(xié)議支持得不夠好。個(gè)人感覺類似Kerberos的機(jī)制在互聯(lián)網(wǎng)中可能過于復(fù)雜了。我感覺單純的ticket機(jī)制,過于局限于基于加密解密的安全了,感覺上SAML的Assertion概念更好,Assertion可以包括認(rèn)證、授權(quán)以及屬性信息。

    -------------


    --------------------------
    09博客園紀(jì)念T恤
    新聞:Wordpress發(fā)布實(shí)時(shí)RSS技術(shù) 推動(dòng)實(shí)時(shí)網(wǎng)絡(luò)發(fā)展
    網(wǎng)站導(dǎo)航: 博客園首頁  個(gè)人主頁  新聞  社區(qū)  博問  閃存  找找看
    posted @ 2009-09-09 01:17 溫少的日志 閱讀(667) | 評(píng)論 (1)編輯 收藏
     
    現(xiàn)在很多開源項(xiàng)目在使用LOG的時(shí)候做了不好的示范--在基類中實(shí)例化的方式使用LOG,而不是靜態(tài)變量。

    例如:

    class Base  {
         private final Log LOG = LogFactory.getLog(this.getClass());
    }

    class Derived  {
        public void foo() {
               if (LOG.isDebugEnabled()) LOG.debug("foo");
        }
    }

    這種用法,當(dāng)類被繼承的時(shí)候,LOG就完全亂了。spring、struts都有這樣的問題。

    正確的使用方式應(yīng)該是直接靜態(tài)化聲明LOG。

    例如:

    class DerivedA  {
         private final static Log LOG = LogFactory.getLog(DerivedA.class);
    }



    --------------------------
    盛大招聘.Net開發(fā)工程師
    經(jīng)典好書:.NET框架程序設(shè)計(jì)(修訂版)
    新聞:2008年最精彩科技圖片:電流運(yùn)動(dòng)模擬圖居首
    導(dǎo)航:博客園首頁  知識(shí)庫  新聞  招聘  社區(qū)  小組  博問  網(wǎng)摘  找找看
    文章來源:http://www.cnblogs.com/jobs/archive/2009/01/05/1368894.html
    posted @ 2009-01-05 10:49 溫少的日志 閱讀(2473) | 評(píng)論 (13)編輯 收藏
     
    Eclipse包含很多插件,插件之間有復(fù)雜的依賴關(guān)系,如果使用單獨(dú)下載安裝的方式,容易遺失部分需要依賴的插件。

    在Ecliipse的Software Update功能中安裝插件,能夠解決插件依賴的問題,但是在Eclipse 3.4之前的版本,Software Update不能夠多線程同時(shí)下載,遇到網(wǎng)速較慢的更新站點(diǎn)時(shí),需要漫長(zhǎng)的等待,有時(shí)候安裝一個(gè)插件,需要數(shù)個(gè)小時(shí),甚至更久。

    在Eclipse 3.4之后,Software Update有了很大的改變,可以多線程下載了,但是不能手工選擇鏡像,它會(huì)笨笨的選擇一些很慢的站點(diǎn),效果變得更差了,下載速度時(shí)快時(shí)慢,但是經(jīng)常都比以前手工選擇鏡像要慢。經(jīng)常選擇一些只有數(shù)百B速度的下載站點(diǎn),令人抓狂!

    所以說,Eclipse 3.4的Software Update功能依然令失望。

    期待數(shù)年,終于盼來了新版的Software Update功能,但是新版的更差了,哎。。。

    posted @ 2008-07-10 03:49 溫少的日志 閱讀(3658) | 評(píng)論 (8)編輯 收藏
     
         摘要: 我們?cè)陂_發(fā)中,經(jīng)常需要遍歷一個(gè)目錄下的所有文件,常用的辦法就是使用一個(gè)函數(shù)遞歸遍歷是常用的辦法。但是遞歸函數(shù)的缺點(diǎn)就是擴(kuò)展不方便,當(dāng)然你對(duì)這個(gè)函數(shù)加入一個(gè)參數(shù)FileHandler,這樣擴(kuò)展性稍好一些,但是仍然不夠好,比如說,不能根據(jù)遍歷的需要中途停止遍歷,加入Filter等等。我實(shí)現(xiàn)了一個(gè)FileIterator,使得遍歷一個(gè)目錄下的文件如何遍歷一個(gè)集合中的元素一般操作。  閱讀全文
    posted @ 2008-06-05 07:56 溫少的日志 閱讀(1882) | 評(píng)論 (2)編輯 收藏
     

    http://openjdk.java.net/上的Announcements:

    2008/04/28 New Project approved: More New I/O APIs for the Java Platform

    包括內(nèi)容:
    • 4313887 New I/O: Improved filesystem interface
    • 4640544 New I/O: Complete socket-channel functionality
    • 4607272 New I/O: Support asynchronous I/O

    讓人期待太久太久了,終于來了,Java在大規(guī)模并發(fā)、高性能方面又進(jìn)一步,JSR 203應(yīng)該會(huì)在JDK 7中實(shí)現(xiàn),屆時(shí)隨著JDK 7的發(fā)布,將會(huì)有更多的基礎(chǔ)軟件使用Java實(shí)現(xiàn),而且有極好的性能。

    在磁盤I/O和網(wǎng)絡(luò)大規(guī)模并發(fā)I/O方面都會(huì)得到更好的性能。

    可以預(yù)見受益的程序:
    1、WEB服務(wù)器 Tomcat、Jetty等,在Windows下,Java將可以使用IOCP,而不是現(xiàn)在nio所用的select,網(wǎng)絡(luò)并發(fā)性能將會(huì)得到大幅度提升。在Linux下則應(yīng)該改變不多,畢竟linux現(xiàn)在并發(fā)最好性能的網(wǎng)絡(luò)I/O EPOLL,JDK 6.0 nio的缺省實(shí)現(xiàn)就是epoll。
    2、數(shù)據(jù)庫應(yīng)用程序。如Derby、Berkeley DB Java Edition等使用Java實(shí)現(xiàn)的數(shù)據(jù)庫,性能將會(huì)得到更好的提升,有望能夠誕生和Oracle、SQL Server一樣強(qiáng)大的100% Pure Java的數(shù)據(jù)庫系統(tǒng)。
    3、其他網(wǎng)絡(luò)應(yīng)用程序。例如DNS、LDAP等,隨著MINA之類的框架更強(qiáng)大和JDK的原生支持,將會(huì)越來越多的服務(wù)器程序使用Java實(shí)現(xiàn)。

    posted @ 2008-05-09 02:54 溫少的日志 閱讀(1758) | 評(píng)論 (3)編輯 收藏
     

    在新項(xiàng)目中,除了一些框架所依賴的配置文件使用XML外,基本沒有使用XML。JSON基本替代了原來XML在程序內(nèi)的位置。在以前,我們不愿意使用一種私有的格式,于是選擇了XML。選擇XML的理由,可能是大家都用它,所以我們也用它。

    XML 是一種很好的技術(shù),但是目前的情況來看,XML被濫用了,SOAP是XML被濫用的一種典型,程序內(nèi)部的表示使用XML也是濫用的一種典型。看到的一種情況,一個(gè)對(duì)象toString使用XML格式輸出,導(dǎo)致日志文件十分羅嗦,調(diào)試時(shí),在watch窗口中看到一大堆<tag>。

    在新項(xiàng)目中,認(rèn)真考慮這種情況,找到了另外一種選擇,那就是JSON。選擇JSON的理由很充分:
    1、JSON的解釋性能要比XML要好,要簡(jiǎn)潔緊湊。
    2、可讀性要比XML好。JSON本身就是JavaScript的語法,和程序員的思維,而非文檔編寫的思維。
    3、JavaScript原生支持,客戶端瀏覽器不需要為此使用額外的解釋器,在web環(huán)境中使用特別合適。

    在java中使用json,目前需要注意一些情況:
    1、目前開源的JSON-LIB代碼質(zhì)量不好,最好是在此基礎(chǔ)之上修改一個(gè)版本,或者自己重新開發(fā)一個(gè)版本。
    2、使用new Date的方式替代JSON-LIB中的{year:2007, month:12, ....}之類的方式
    3、JSON-LIB中,object的propertyName在輸出的時(shí)候,都帶上"",例如{"name": "溫少"}, 其中name是的雙引號(hào)是不必要的,在輸出時(shí)應(yīng)該判斷,不需要的就是就不加上"",減少網(wǎng)絡(luò)流量。
    4、JSON的解釋器中,應(yīng)該支持簡(jiǎn)單的表達(dá)式,例如new Date()、new Date(2939234723)之類的,這使得JSON的表達(dá)能力會(huì)更強(qiáng)一些。
    5、JSON應(yīng)該分兩種,一種只支持簡(jiǎn)單格式,類似開源的JSON-LIB,一種是通過JavaScript解釋器來實(shí)現(xiàn)的。后者在程序中傳輸數(shù)據(jù)時(shí),能夠得到更強(qiáng)大的表達(dá)能力,但是也會(huì)導(dǎo)致安全問題,需要慎重使用。
    posted @ 2008-03-08 14:24 溫少的日志 閱讀(3683) | 評(píng)論 (12)編輯 收藏
     

    1、 XP中的結(jié)對(duì)編程。XP編程中,有一些思想總結(jié)的很好,例如測(cè)試驅(qū)動(dòng),但又有極度的荒唐的就是結(jié)對(duì)編程。結(jié)對(duì)編程是我看到過的最荒唐最可笑的軟件工程方 法,兩倍的投入,一半的產(chǎn)出,可謂事倍功半。以前看結(jié)對(duì)編程只是覺得荒唐可笑,后來看了李安的電影《斷背山》,覺得以“斷背”來形容結(jié)對(duì)編程最適合了,結(jié) 對(duì)編程簡(jiǎn)直就是專門為“男同志”們度身定做的軟件工程方法,你想一對(duì)“男同志”,每天手牽手背靠背進(jìn)行“結(jié)對(duì)編程”,是多么“浪漫有趣”的事情。不過這只 對(duì)“男同志”們的浪漫有趣,對(duì)工作本身一點(diǎn)也不有趣!
    --------------

    2、JDO投票鬧劇(2004-2005)。 一個(gè)通過黑客式靜態(tài)AOP方式旁門左道實(shí)現(xiàn)的持久化技術(shù)JDO,竟然會(huì)被一些人追捧,這本身就是一個(gè)很荒唐的事情了。在JCP的投票中,JDO被否決了, 這一點(diǎn)也不奇怪,奇怪的是投票結(jié)果出來之后的鬧劇。一些人以“政治陰謀論”來說事,說JDO不被通過,是因?yàn)檎卧颍羌夹g(shù)原因,這個(gè)荒唐的理由竟然 被社區(qū)的很多人相信了,一片聲討,JCP迫于壓力,重新投票,通過了JDO相關(guān)的JSR。但是JDO并沒有因此有一點(diǎn)點(diǎn)起色,一直沉淪至今。JDO通過靜 態(tài)AOP(enhance)的方式使得代碼無法調(diào)試,就單這一點(diǎn),就足以使JDO永遠(yuǎn)無法流行。

    這件事情很明確表明兩點(diǎn):1)、不要相信一些技術(shù)作家的判斷力;2)、普通的大眾沒有判斷能力,會(huì)人云亦云。

    當(dāng)年荒唐的文章選錄:
    《程序員》2005年第2期 http://blog.csdn.net/gigix/archive/2005/01/21/262163.aspx
    ---------------
    posted @ 2008-02-09 15:39 溫少的日志 閱讀(989) | 評(píng)論 (5)編輯 收藏
     

    竟 然64個(gè)annotation,沒有分類,放在同一個(gè)package下,同一個(gè)package(javax.persistance)還有其他java文 件,共有88個(gè)java文件。不看內(nèi)容本身,單從表面,都覺得這是混亂不堪的事情。這是那個(gè)豬頭的杰作?glassfish上下載的源碼中,這些java 文件似乎都沒有author,估計(jì)也不好意思把名字放出來見人吧!

    ------

    覺得對(duì)象關(guān)系存儲(chǔ)方面一直沒有突破,也沒有好的產(chǎn)品出來,其中一個(gè)原因,就是從沒有過優(yōu)秀的工程師投身過這個(gè)領(lǐng)域。關(guān)系數(shù)據(jù)庫為什么能夠一直堅(jiān)守領(lǐng)地,成為絕大多數(shù)商業(yè)應(yīng)用的基石,其中一個(gè)原因就是有過大量的精英投身于此,包括兩個(gè)圖靈獎(jiǎng)獲得者。

    關(guān) 系數(shù)據(jù)庫,為了描述關(guān)系,創(chuàng)造一門SQL語言,將關(guān)系一些操作,例如投影(select)、選擇(where)、分組(group by)等等,抽象得形象易懂,功能強(qiáng)大。對(duì)于數(shù)據(jù)的操作,SQL語言是最強(qiáng)大,也是最方便的,也是最易于使用的。一些非程序員的IT從業(yè)人員,非計(jì)算機(jī)專 業(yè)的人員都能夠熟練掌握SQL。

    OO和Relational都是偉大的技術(shù),從計(jì)算機(jī)最高榮譽(yù)獎(jiǎng)可以看出這兩個(gè)技術(shù)的偉大。OO的圖靈獎(jiǎng)獲得者是三個(gè),Relational的圖靈獎(jiǎng)獲得者是兩個(gè)。

    面向?qū)ο蠹夹g(shù)自1967年simula引進(jìn)以來,所想披靡,93年-98年從C++開始流行,然后到Java,成為主流編程技術(shù)。Relational沒有OO那么輝煌,但是在數(shù)據(jù)存儲(chǔ)方面的地位固如磐石,長(zhǎng)期占據(jù)絕對(duì)的地位。

    曾 經(jīng)OO技術(shù)涉足于數(shù)據(jù)存儲(chǔ)領(lǐng)域,但終究沒有成功。面向?qū)ο髷?shù)據(jù)庫的變現(xiàn)總是差強(qiáng)人意,面向?qū)ο蟮姆绞讲僮鲾?shù)據(jù),總是不如使用關(guān)系那么方便,那么靈活,那么 易于使用,那么好的性能。于是人們?cè)跀?shù)據(jù)存儲(chǔ)和處理方面,不在青睞面向?qū)ο蠹夹g(shù),而是仍然使用關(guān)系方式,使用SQL語言,使用關(guān)系運(yùn)算操作數(shù)據(jù)。面向?qū)ο? 數(shù)據(jù)庫成了曇花一現(xiàn)的東西,并且可能永遠(yuǎn)都不會(huì)再流行了。

    OO成了主流編程技術(shù),Relational占據(jù)了絕對(duì)的數(shù)據(jù)存儲(chǔ)地位,這兩大技術(shù)需要交互,需要橋接,這需要OR-Mapping。Relational雖然好,但我們也要與時(shí)俱進(jìn),所以也需要OR-Mapping。

    但 是,做OR-Mapping時(shí),不積極吸取relational方式對(duì)數(shù)據(jù)處理的靈活性、方便性、簡(jiǎn)單性,而只強(qiáng)調(diào)Relational和對(duì)象之間的的 Mapping,試圖以面向?qū)ο蟮姆绞讲僮鲾?shù)據(jù),這是錯(cuò)誤的方向。以前的EJB、現(xiàn)在Hibernate、JPA都犯了同樣的錯(cuò)誤,試圖以更面向?qū)ο蟮姆? 式操作數(shù)據(jù),從而導(dǎo)致復(fù)雜混亂的模型,這也是JPA的現(xiàn)狀吧。例如user.getGroup(),目前的ORM試圖以純OO的方式操作數(shù)據(jù),所引起的 LazyLoad、n+1等問題,使得事情變得復(fù)雜而且混亂不堪。

    一些開發(fā)人員,去學(xué)習(xí)Hibernate,不學(xué)習(xí)SQL,有人提倡,只需要了解面向?qū)ο缶幊碳夹g(shù),不需要了解關(guān)系技術(shù),亦屬于本末倒置。需求人員都會(huì)用的SQL語言,對(duì)數(shù)據(jù)操作最方便最簡(jiǎn)單最強(qiáng)大的SQL語言,竟然成了令人生畏的紙老虎,可笑啊。

    -------------

    以下是過去的一些業(yè)界浮躁不理智:

    1、面向?qū)ο髷?shù)據(jù)庫。曾被熱衷而吹捧,面向?qū)ο髷?shù)據(jù)庫的變現(xiàn)總是差強(qiáng)人意,面向?qū)ο蟮姆绞讲僮鲾?shù)據(jù),總是不如使用關(guān)系那么方便,那么靈活,那么易于使用,那么好的性能。于是人們?cè)跀?shù)據(jù)存儲(chǔ)和處 理方面,不在青睞面向?qū)ο蠹夹g(shù),而是仍然使用關(guān)系方式,使用SQL語言,使用關(guān)系運(yùn)算操作數(shù)據(jù)。面向?qū)ο髷?shù)據(jù)庫成了曇花一現(xiàn)的東西,并且可能永遠(yuǎn)都不會(huì)再 流行了。

    2、 JDO投票鬧劇。2004-2005年,JDO的JSR在JCP投票被否決的,無聊者在Java社區(qū)以及媒體發(fā)起鬧事,陰謀論其為政治謀殺,幾大公司是的 迫于形象,重新投票使得JDO被通過,但JDO這種靜態(tài)AOP叫雕蟲小計(jì)式技術(shù),不單開發(fā)過程不方便,而且會(huì)使得"enhance"之后的代碼不可調(diào)試。 這完全是對(duì)開發(fā)者不友好的技術(shù),沒有前途的技術(shù),竟然會(huì)有人為它在JCP投票不通過鳴不平。這件事情使得我更堅(jiān)信一點(diǎn),不要相信那些技術(shù)編輯的判斷力。

    3、 AOP。也是最近這幾年流行的一個(gè)名詞了。起了一個(gè)和OOP相似的名字,但是和偉大的OOP相比,它完全不算是什么。AOP只是一種很小很小的技巧而已, 靜態(tài)的AOP是黑客式的插入代碼,會(huì)導(dǎo)致代碼不可調(diào)試,動(dòng)態(tài)的AOP能力有限,AOP最常被引用例子“日志AOP”是不合適,有用的日志通常是精心設(shè)計(jì) 的,AOP方式的日志在生產(chǎn)環(huán)境中基本上是不可用。OO這么多年,這么為偉大,人們總是希望自己能做點(diǎn)什么和偉大的OO相比,于是命名為AOP,這是一個(gè) 可笑的名字,前些年還有人談?wù)撁嫦驅(qū)ο蟮奈磥硎敲嫦蚴聦?shí),也是同樣的可笑。AOP有價(jià)值,但它是一種小技巧,和名字不般配。

    --------------

    目前在流行,但是可能是不理智的技術(shù):

    1、hibernate之類的ORM,試圖以面向?qū)ο蠓绞讲僮鲾?shù)據(jù),和面向?qū)ο髷?shù)據(jù)庫一樣,重蹈覆轍。
    2、Ruby,一個(gè)小腳本語言,只是因?yàn)閯?dòng)態(tài)類型、mixin之類的功能,還沒有被證明有生產(chǎn)力,有效益可用的腳本語言,就被媒體吹到天上去。Ruby有價(jià)值,但是最終結(jié)果會(huì)離大家的期待相差甚遠(yuǎn)。
    posted @ 2008-02-02 02:56 溫少的日志 閱讀(5259) | 評(píng)論 (19)編輯 收藏
     



    中國最大的在線記賬及商務(wù)管理平臺(tái)—金蝶“友商網(wǎng)”(
    www.youshang.com)正式上線!請(qǐng)立刻體驗(yàn)!
    posted @ 2007-11-29 15:42 溫少的日志 閱讀(1471) | 評(píng)論 (13)編輯 收藏
     
         摘要: 本文描述一種ID生成算法  閱讀全文
    posted @ 2007-11-16 07:09 溫少的日志 閱讀(2731) | 評(píng)論 (8)編輯 收藏
     
         摘要: 本文介紹流行的非阻塞算法關(guān)鍵思想Compare And Set在數(shù)據(jù)庫開發(fā)中的應(yīng)用  閱讀全文
    posted @ 2007-11-13 06:33 溫少的日志 閱讀(1456) | 評(píng)論 (4)編輯 收藏
     
    由于在實(shí)際工作中使用到了mina,所以一直關(guān)注其mail-list。

    最近mina的mail-list討論的一個(gè)問題,就是提供的manual close connector,這個(gè)問題可害慘我了。

    原來的Connector,無論是SocketConnector或者VmPipeConnector,都是沒有提供close方法的,而且不會(huì)自動(dòng)釋放。

    原來做得一個(gè)網(wǎng)絡(luò)程序客戶端,每次重新創(chuàng)建的時(shí)候,都會(huì)new SocketConnector,可是,SocketConnector不會(huì)被GC回收的,所使用的線程和內(nèi)存都不會(huì)自動(dòng)釋放,這個(gè)程序在服務(wù)器斷開時(shí)會(huì)重連,于是,當(dāng)服務(wù)器重啟或者網(wǎng)絡(luò)中斷時(shí),內(nèi)存泄漏就產(chǎn)生了,程序慢慢的占用更多的內(nèi)存,直至崩潰!

    解決此問題的辦法就是,要么使用Singleton,要么使用即將發(fā)布的1.1.3!


    溫少 2007-09-29 21:08 發(fā)表評(píng)論
    posted @ 2007-09-29 21:12 溫少的日志 閱讀(1205) | 評(píng)論 (0)編輯 收藏
     
    使用maven2一段時(shí)間了,我基本把我自己能夠遷移的project都轉(zhuǎn)換為maven2 project,以下是我的一點(diǎn)感想。

    (原作者溫少,轉(zhuǎn)載請(qǐng)注明)

    亂世盼英雄


    現(xiàn)在的軟件開發(fā),比過去的軟件開發(fā)要復(fù)雜得多。包括在參與開發(fā)的人數(shù)、代碼規(guī)模、復(fù)雜的需求、依賴包的復(fù)雜性、使用到更多的技術(shù)、多個(gè)項(xiàng)目之間的復(fù)雜依賴關(guān)系。

    現(xiàn)在的開發(fā)人員,要掌握的技術(shù)要比過去的開發(fā)人員要多,不是現(xiàn)在的開發(fā)人員比以前的開發(fā)人員本身更優(yōu)秀,而是擁有更多的資料、更多的學(xué)習(xí)機(jī)會(huì)、更多更大規(guī)模的時(shí)間,同時(shí)軟件行業(yè)也在發(fā)展。說一句題外話,老程序員,如果不與時(shí)俱進(jìn),靠老本,是無法和新一代程序員競(jìng)爭(zhēng)的,當(dāng)然,老程序員,擁有更多的經(jīng)驗(yàn),掌握新技術(shù)的速度更快,這又是另外一回事。

    開發(fā)人員掌握的技術(shù)更復(fù)雜了,項(xiàng)目用得的技術(shù)自然也是更復(fù)雜,例如一個(gè)web項(xiàng)目,可能使用到很多技術(shù),面向?qū)ο蟆⒎盒汀r-mapping、依賴注入(spring-framework)、全文檢索(lucene)、數(shù)據(jù)庫、集群、工作流、web service等等。

    由于使用了多種技術(shù),這些技術(shù)可能是JDK提供的,也可能是第三方開源組織提供的,或者不同的商業(yè)公司提供的。

    于是出現(xiàn)了一個(gè)新的難題,就是包依賴復(fù)雜性。以前,你很難想象你的代碼依賴數(shù)十個(gè)不同開源組織、商業(yè)公司提供的庫。例如,我們經(jīng)常使用的log4j、junit、easymock、ibatis、springframework,每個(gè)組件都有悠久的歷史,存在不同的版本,他們之間版本還有依賴關(guān)系。

    項(xiàng)目依賴的復(fù)雜性,經(jīng)常的,一個(gè)較大部門有10-30個(gè)項(xiàng)目是常事,項(xiàng)目之間有不同版本的依賴關(guān)系,部門與部門之間的項(xiàng)目也存在復(fù)雜的版本依賴關(guān)系。

    Eclipse本身提供Project的依賴,但是簡(jiǎn)單的依賴顯然解決不了問題。例如Project B依賴Project A,Project A依賴第三方的jar包abc-1.0.jar,那么需要在兩個(gè)項(xiàng)目的lib下都存放abc-1.0.jar,這產(chǎn)生冗余,當(dāng)Project數(shù)量多起來,這個(gè)冗余就產(chǎn)生了管理問題,如果需要將abc-1.0.jar升級(jí)為abc-1.1.jar,則需要在兩個(gè)Project中同時(shí)修改,如果Project數(shù)量達(dá)到10個(gè)以上,而且是不同項(xiàng)目組維護(hù)的項(xiàng)目,這個(gè)就是非常麻煩的事情。而且Project A修改依賴,為啥需要Project B也作相應(yīng)的修改呢?

    需要解決此問題,就需要在Project A的包中描述其依賴庫的信息,例如在META-INFO記錄所以來的abc-1.0.jar等。Eclipse的plug-in擁有類似的方案,但是這樣一來,就使得開發(fā)Project B的項(xiàng)目組,需要把Project A的代碼從源代碼庫中check out出來。在依賴鏈末端的項(xiàng)目組是很慘的。

    由于Project數(shù)量眾多,關(guān)系復(fù)雜,dailybuild的ant腳本編寫成了很麻煩的事情,使用Project依賴的方式,更加使得編寫dailybuild ant script是非常痛苦的事情。

    當(dāng)然也可以不使用project依賴的方式,而使用artifact lib的依賴方式,但是artifact lib的依賴方式,就是同時(shí)修改多個(gè)project,互相調(diào)試時(shí)帶來了痛苦。

    在以前,我們面臨這些問題時(shí),唯一的感覺就是,這事情TMD的太麻煩,幾乎是失控了。

    maven的出現(xiàn),解決這種問題看到了希望。maven出現(xiàn)的原因就是,現(xiàn)在的開發(fā)管理復(fù)雜度達(dá)到了一定程序,需要專門的開發(fā)管理工具,這樣的工具需要涵蓋開發(fā)的各個(gè)階段,包括工程建立、配置依賴管理、編譯、測(cè)試、產(chǎn)生分析報(bào)告、部署、產(chǎn)生制品等階段。目前,各個(gè)階段的工具都存在,但是不是集成的,對(duì)使用帶來了很大麻煩。maven集成了這些工具,提高了統(tǒng)一的環(huán)境,使得使用更簡(jiǎn)單。

    現(xiàn)在maven非常流行了,apache上所有java project都已經(jīng)build by maven,其他跟進(jìn)的開源項(xiàng)目非常多,例如mule、hibernat等等,商業(yè)公司也很多在采用,sun公司提供有maven2 repository。

    現(xiàn)在,2007年,如果你還沒采用maven project,你可能需要思考一下,是否你使用了不恰當(dāng)?shù)姆绞焦芾淼拇a,或者你落伍了?

    maven的一些常用任務(wù)

    compile 編譯代碼
    test 運(yùn)行單元測(cè)試
    package 打包代碼
    site 產(chǎn)生報(bào)告,例如java doc、junit的通過率報(bào)告和覆蓋率報(bào)告、findbugs的分析報(bào)告等等。
    assembly 使用需求產(chǎn)生assembly,例如把生成一個(gè)程序目錄,包括bin、config、lib、logs,把依賴包放在lib中。
    deploy 部署制品到repository中。

    這些都是常用的任務(wù),在以前編寫腳本很麻煩,現(xiàn)在在maven中,一切都是很簡(jiǎn)單,需要仔細(xì)設(shè)置時(shí)功能又強(qiáng)大到令人驚嘆,例如site的fml,assembly。

    maven資源庫

    maven官方提供了一個(gè)常用lib的資源庫,包括apache的所有java項(xiàng)目,開源常用的基本都能夠找到,例如mule、c3p0、easymock、hibernate、springframework、json等等,版本齊全,任你挑選。

    可以部署本地資源庫代理提高下載速度。使用maven proxy。

    maven體系結(jié)構(gòu)


    maven使用plug-in的體系,使用很好的自動(dòng)更新策略,本身用到的jar都是lazy download的,可以指定download的repository。這樣,初始下載的maven是一個(gè)很小的程序,使用的時(shí)候從本地的資源庫或者本地代理資源庫高速下載lib。maven的插件體系,充分利用了internet的資源豐富和局域網(wǎng)的高速帶寬,使用本地repository時(shí),可以享受到每秒鐘數(shù)M的下載速度,感覺就是,人生真是美妙!

    elcipse的plug-in體系,就不是那么好用了,我們使用eclipse的find and install功能下載或者更新插件時(shí),慢如蝸牛,依賴缺失時(shí)的煩惱,更新一個(gè)plug-in,可能耗費(fèi)你數(shù)個(gè)小時(shí),第三方的plug-in的下載服務(wù)器可能更慢,例如subversive的plugin-in,有一次我花了兩天還沒下載好,只好使用下載工具下載好,copy到plug-in目錄下。此時(shí),我們總是感嘆,人生總是有很多煩惱事啊!

    相比之下,高下立判!在此我不是說eclipse的plug-in體系結(jié)構(gòu)設(shè)計(jì)不好,eclipse的插件體系非常優(yōu)秀,但是還有很大改進(jìn)空間!




    溫少 2007-09-24 08:34 發(fā)表評(píng)論
    posted @ 2007-09-24 08:34 溫少的日志 閱讀(2922) | 評(píng)論 (7)編輯 收藏
     
    在beep4j上作了一些修改,并且在此之上實(shí)現(xiàn)了一個(gè)基于BEEP協(xié)議的服務(wù)器框架。

    BEEP協(xié)議提供了Session、Channel、Greeting、Profile、Frame等概念,這些基礎(chǔ)概念之上,很容易進(jìn)行更高級(jí)的應(yīng)用層協(xié)議設(shè)計(jì)。

    BEEP協(xié)議的特征和能力


    長(zhǎng)連接
    對(duì)等通訊
    請(qǐng)求\應(yīng)答式交互
    在一個(gè)Session中創(chuàng)建多個(gè)獨(dú)立的傳輸通道(Channel)
    在一個(gè)通道中進(jìn)行多個(gè)異步請(qǐng)求(滑動(dòng)窗口)
    可以使用不同的消息編碼方式,包括二進(jìn)制、文本、XML等,類似SMTP的MIME,使得可以在高效的二進(jìn)制、易懂的文本之間作出選擇。

    這是一個(gè)在傳輸層和應(yīng)用層之間的協(xié)議,應(yīng)用場(chǎng)景很廣泛,RFC標(biāo)準(zhǔn)化,官方網(wǎng)站為http://www.beepcore.org/。很多公司都有相應(yīng)的支持,包括IBM。在不同語言下都是相應(yīng)的實(shí)現(xiàn),包括C、Java、Python、Ruby、JavaScript Beep client等等。

    關(guān)于ContentType和Codec


    在Java程序之間通訊,前期可能不希望作更多的協(xié)議編碼、解碼工作,使用spring bean xml格式傳輸是一種方式。

    在一些對(duì)效率不是特別高,又不喜歡使用機(jī)器友好的XML的場(chǎng)景,可以使用JSON的編碼方式。

    在一些對(duì)效率要求很高的場(chǎng)景,ASN.1或者自定義的二進(jìn)制編碼格式。

    甚至使用土土的序列化編碼方式





    溫少 2007-09-22 08:07 發(fā)表評(píng)論
    posted @ 2007-09-22 08:07 溫少的日志 閱讀(908) | 評(píng)論 (0)編輯 收藏
     

    匆忙寫成,以后會(huì)慢慢補(bǔ)充

    請(qǐng)用力一擊

    中等規(guī)模的并發(fā)程序設(shè)計(jì)
    http://www.cnblogs.com/Files/jobs/2007-5-9-concurrent-ppt.rar

    2007-5-10修改版(帶參考文檔)
    http://www.cnblogs.com/Files/jobs/2007-5-10-concurrent-ppt.rar

    posted @ 2007-05-08 08:15 溫少的日志 閱讀(571) | 評(píng)論 (1)編輯 收藏
     
    2007年4月刊《程序員》,專題為“多核時(shí)下的軟件開發(fā)”。《程序員》并非陽春白雪,它面向大眾程序員。面向大眾的《程序員》介紹多核、并發(fā),也意味著并發(fā)程序設(shè)計(jì)的開始進(jìn)入中國大眾程序員的視野。

    并發(fā)程序設(shè)計(jì),在很多的書籍或者文章中,都會(huì)提到他的一個(gè)特點(diǎn),復(fù)雜。這個(gè)特性,也導(dǎo)致了在以往并發(fā)程序設(shè)計(jì)只為高級(jí)程序員所專用。

    復(fù)雜度并非事物的固有屬性,并發(fā)程序設(shè)計(jì)的復(fù)雜,是我們主觀認(rèn)為。我們認(rèn)為并發(fā)程序設(shè)計(jì)復(fù)雜,是因?yàn)槲覀冞€沒有掌握一些使其簡(jiǎn)單化、清晰化的方法。當(dāng)我們掌握相關(guān)方法,研究徹底,并發(fā)就會(huì)變得簡(jiǎn)單。這個(gè)過程已經(jīng)開始了。

    以 往,我們需要直接使用一些低級(jí)并發(fā)概念來構(gòu)造系統(tǒng),不斷發(fā)明輪子,容易出錯(cuò),難以調(diào)試,這種的并發(fā)程序設(shè)計(jì)當(dāng)然復(fù)雜,因此也只能為高級(jí)程序員所專用。如此 環(huán)境,就如同Dijkstra給我們帶來結(jié)構(gòu)化程序設(shè)計(jì)之前的世界一般。很幸運(yùn)的是,一些軟件業(yè)的先驅(qū)們,已經(jīng)抽象出一些概念,能夠使得并發(fā)程序設(shè)計(jì)簡(jiǎn)單 化,清晰化。例如Future、Lock-free思想等。

    在主流編程語言中,Java走在最前頭,理念領(lǐng)先,提供了實(shí)用的庫。在 Java SE 5.0中就提供了util.concurent包,包括了Future、Executor、BlockingQueue等,一系列l(wèi)ock-free的數(shù) 據(jù)結(jié)構(gòu),例如ConcurrentMap。包括并發(fā)流程控制工具類:CountDownLatch、CycliBarrier。還有精巧好用的 DelayQueue(參考我之前寫過的文章http: //www.cnblogs.com/jobs/archive/2007/04/27/730255.html)。使用這些概念以及提供的模式,能夠使 得編寫并發(fā)程序簡(jiǎn)單化。

    C++中,Herb Sutter在Visual C++中加入了很多支持并發(fā)的語法特性,包括atomic、future等。boost的線程庫開始引入了第一個(gè)高級(jí)概念barrier。

    Windows 平臺(tái)本身提供了功能強(qiáng)大的并發(fā)API,包括WaitForSingle系列,WaitForMulti系列,Auto和Manual模式的Event等 等。.NET平臺(tái)基本沒有任何自有的并發(fā)庫和工具類,完全是Windows API的簡(jiǎn)單封裝。可以這么說,.NET的類庫沒有為并發(fā)作任何事情,完全吃Windows API的老本。

    如同Herb Sutter認(rèn)為,我們很幸運(yùn)處于并經(jīng)歷這個(gè)軟件大變革(并發(fā))。并發(fā)進(jìn)入主流這個(gè)過程將會(huì)延續(xù)數(shù)年,Herb Sutter認(rèn)為是2007-2012。
    參考我以前寫的一篇文章(Herb Sutter的一些觀點(diǎn) http://www.cnblogs.com/jobs/archive/2006/11/12/558078.html)

    類 似的場(chǎng)景也有,早期面向?qū)ο蠹夹g(shù),也只為少數(shù)高級(jí)程序員所掌握,現(xiàn)在剛?cè)腴T的程序員都能說上一大通。數(shù)據(jù)結(jié)構(gòu)算法也是,早期只為少數(shù)優(yōu)秀程序員所掌握,但 現(xiàn)在主流的開發(fā)環(huán)境中就包括了主要的數(shù)據(jù)結(jié)構(gòu)和算法,會(huì)用的人一把一把,會(huì)用List、Hashtable、快速排序一點(diǎn)也不酷。并發(fā)程序設(shè)計(jì)也一樣,將 不再是陽春白雪!

    面向?qū)ο蠹夹g(shù)在最初在Simula語言中引進(jìn),顧名思義,最初樸素的面向?qū)ο笏枷刖褪悄M,在程序中模擬真實(shí)世界。這種 “模擬”,使得程序的組織清晰化,簡(jiǎn)單化。但真實(shí)世界是充滿著并發(fā)。真實(shí)世界的并發(fā)要比虛擬環(huán)境中的并發(fā)要復(fù)雜的多,但是人們輕松應(yīng)付,由此,我們有足夠 的理由相信,并發(fā)程序設(shè)計(jì)將不會(huì)是一種復(fù)雜難掌握的技術(shù)。
    posted @ 2007-05-01 08:54 溫少的日志 閱讀(1405) | 評(píng)論 (2)編輯 收藏
     

    我們談一下實(shí)際的場(chǎng)景吧。我們?cè)陂_發(fā)中,有如下場(chǎng)景

    a) 關(guān)閉空閑連接。服務(wù)器中,有很多客戶端的連接,空閑一段時(shí)間之后需要關(guān)閉之。
    b) 緩存。緩存中的對(duì)象,超過了空閑時(shí)間,需要從緩存中移出。
    c) 任務(wù)超時(shí)處理。在網(wǎng)絡(luò)協(xié)議滑動(dòng)窗口請(qǐng)求應(yīng)答式交互時(shí),處理超時(shí)未響應(yīng)的請(qǐng)求。

    一種笨笨的辦法就是,使用一個(gè)后臺(tái)線程,遍歷所有對(duì)象,挨個(gè)檢查。這種笨笨的辦法簡(jiǎn)單好用,但是對(duì)象數(shù)量過多時(shí),可能存在性能問題,檢查間隔時(shí)間不好設(shè)置,間隔時(shí)間過大,影響精確度,多小則存在效率問題。而且做不到按超時(shí)的時(shí)間順序處理。

    這場(chǎng)景,使用DelayQueue最適合了。

    DelayQueue 是java.util.concurrent中提供的一個(gè)很有意思的類。很巧妙,非常棒!但是java doc和Java SE 5.0的source中都沒有提供Sample。我最初在閱讀ScheduledThreadPoolExecutor源碼時(shí),發(fā)現(xiàn)DelayQueue 的妙用。隨后在實(shí)際工作中,應(yīng)用在session超時(shí)管理,網(wǎng)絡(luò)應(yīng)答通訊協(xié)議的請(qǐng)求超時(shí)處理。

    本文將會(huì)對(duì)DelayQueue做一個(gè)介紹,然后列舉應(yīng)用場(chǎng)景。并且提供一個(gè)Delayed接口的實(shí)現(xiàn)和Sample代碼。

    DelayQueue是一個(gè)BlockingQueue,其特化的參數(shù)是Delayed。(不了解BlockingQueue的同學(xué),先去了解BlockingQueue再看本文)
    Delayed擴(kuò)展了Comparable接口,比較的基準(zhǔn)為延時(shí)的時(shí)間值,Delayed接口的實(shí)現(xiàn)類getDelay的返回值應(yīng)為固定值(final)。DelayQueue內(nèi)部是使用PriorityQueue實(shí)現(xiàn)的。

    DelayQueue = BlockingQueue + PriorityQueue + Delayed

    DelayQueue的關(guān)鍵元素BlockingQueue、PriorityQueue、Delayed。可以這么說,DelayQueue是一個(gè)使用優(yōu)先隊(duì)列(PriorityQueue)實(shí)現(xiàn)的BlockingQueue,優(yōu)先隊(duì)列的比較基準(zhǔn)值是時(shí)間。

    他們的基本定義如下
    public interface Comparable<T> {
        
    public int compareTo(T o);
    }

    public interface Delayed extends Comparable<Delayed> {
        
    long getDelay(TimeUnit unit);
    }

    public class DelayQueue<extends Delayed> implements BlockingQueue<E> { 
        
    private final PriorityQueue<E> q = new PriorityQueue<E>();
    }

    DelayQueue內(nèi)部的實(shí)現(xiàn)使用了一個(gè)優(yōu)先隊(duì)列。當(dāng)調(diào)用DelayQueue的offer方法時(shí),把Delayed對(duì)象加入到優(yōu)先隊(duì)列q中。如下:
    public boolean offer(E e) {
        
    final ReentrantLock lock = this.lock;
        lock.lock();
        
    try {
            E first 
    = q.peek();
            q.offer(e);
            
    if (first == null || e.compareTo(first) < 0)
                available.signalAll();
            
    return true;
        } 
    finally {
            lock.unlock();
        }
    }

    DelayQueue的take方法,把優(yōu)先隊(duì)列q的first拿出來(peek),如果沒有達(dá)到延時(shí)閥值,則進(jìn)行await處理。如下:
    public E take() throws InterruptedException {
        
    final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        
    try {
            
    for (;;) {
                E first 
    = q.peek();
                
    if (first == null) {
                    available.await();
                } 
    else {
                    
    long delay =  first.getDelay(TimeUnit.NANOSECONDS);
                    
    if (delay > 0) {
                        
    long tl = available.awaitNanos(delay);
                    } 
    else {
                        E x 
    = q.poll();
                        
    assert x != null;
                        
    if (q.size() != 0)
                            available.signalAll(); 
    // wake up other takers
                        return x;

                    }
                }
            }
        } 
    finally {
            lock.unlock();
        }
    }

    -------------------

    以下是Sample,是一個(gè)緩存的簡(jiǎn)單實(shí)現(xiàn)。共包括三個(gè)類Pair、DelayItem、Cache。如下:

    public class Pair<K, V> {
        
    public K first;

        
    public V second;
        
        
    public Pair() {}
        
        
    public Pair(K first, V second) {
            
    this.first = first;
            
    this.second = second;
        }
    }

    --------------
    以下是Delayed的實(shí)現(xiàn)
    import java.util.concurrent.Delayed;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicLong;

    public class DelayItem<T> implements Delayed {
        
    /** Base of nanosecond timings, to avoid wrapping */
        
    private static final long NANO_ORIGIN = System.nanoTime();

        
    /**
         * Returns nanosecond time offset by origin
         
    */
        
    final static long now() {
            
    return System.nanoTime() - NANO_ORIGIN;
        }

        
    /**
         * Sequence number to break scheduling ties, and in turn to guarantee FIFO order among tied
         * entries.
         
    */
        
    private static final AtomicLong sequencer = new AtomicLong(0);

        
    /** Sequence number to break ties FIFO */
        
    private final long sequenceNumber;

        
    /** The time the task is enabled to execute in nanoTime units */
        
    private final long time;

        
    private final T item;

        
    public DelayItem(T submit, long timeout) {
            
    this.time = now() + timeout;
            
    this.item = submit;
            
    this.sequenceNumber = sequencer.getAndIncrement();
        }

        
    public T getItem() {
            
    return this.item;
        }

        
    public long getDelay(TimeUnit unit) {
            
    long d = unit.convert(time - now(), TimeUnit.NANOSECONDS);
            
    return d;
        }

        
    public int compareTo(Delayed other) {
            
    if (other == this// compare zero ONLY if same object
                return 0;
            
    if (other instanceof DelayItem) {
                DelayItem x 
    = (DelayItem) other;
                
    long diff = time - x.time;
                
    if (diff < 0)
                    
    return -1;
                
    else if (diff > 0)
                    
    return 1;
                
    else if (sequenceNumber < x.sequenceNumber)
                    
    return -1;
                
    else
                    
    return 1;
            }
            
    long d = (getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS));
            
    return (d == 0? 0 : ((d < 0? -1 : 1);
        }
    }



    以下是Cache的實(shí)現(xiàn),包括了put和get方法,還包括了可執(zhí)行的main函數(shù)。
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;
    import java.util.concurrent.DelayQueue;
    import java.util.concurrent.TimeUnit;
    import java.util.logging.Level;
    import java.util.logging.Logger;

    public class Cache<K, V> {
        
    private static final Logger LOG = Logger.getLogger(Cache.class.getName());

        
    private ConcurrentMap<K, V> cacheObjMap = new ConcurrentHashMap<K, V>();

        
    private DelayQueue<DelayItem<Pair<K, V>>> q = new DelayQueue<DelayItem<Pair<K, V>>>();

        
    private Thread daemonThread;

        
    public Cache() {

            Runnable daemonTask 
    = new Runnable() {
                
    public void run() {
                    daemonCheck();
                }
            };

            daemonThread 
    = new Thread(daemonTask);
            daemonThread.setDaemon(
    true);
            daemonThread.setName(
    "Cache Daemon");
            daemonThread.start();
        }

        
    private void daemonCheck() {

            
    if (LOG.isLoggable(Level.INFO))
                LOG.info(
    "cache service started.");

            
    for (;;) {
                
    try {
                    DelayItem
    <Pair<K, V>> delayItem = q.take();
                    
    if (delayItem != null) {
                        
    // 超時(shí)對(duì)象處理
                        Pair<K, V> pair = delayItem.getItem();
                        cacheObjMap.remove(pair.first, pair.second); 
    // compare and remove
                    }
                } 
    catch (InterruptedException e) {
                    
    if (LOG.isLoggable(Level.SEVERE))
                        LOG.log(Level.SEVERE, e.getMessage(), e);
                    
    break;
                }
            }

            
    if (LOG.isLoggable(Level.INFO))
                LOG.info(
    "cache service stopped.");
        }

        
    // 添加緩存對(duì)象
        public void put(K key, V value, long time, TimeUnit unit) {
            V oldValue 
    = cacheObjMap.put(key, value);
            
    if (oldValue != null)
                q.remove(key);

            
    long nanoTime = TimeUnit.NANOSECONDS.convert(time, unit);
            q.put(
    new DelayItem<Pair<K, V>>(new Pair<K, V>(key, value), nanoTime));
        }

        
    public V get(K key) {
            
    return cacheObjMap.get(key);
        }

        
    // 測(cè)試入口函數(shù)
        public static void main(String[] args) throws Exception {
            Cache
    <Integer, String> cache = new Cache<Integer, String>();
            cache.put(
    1"aaaa"3, TimeUnit.SECONDS);

            Thread.sleep(
    1000 * 2);
            {
                String str 
    = cache.get(1);
                System.out.println(str);
            }

            Thread.sleep(
    1000 * 2);
            {
                String str 
    = cache.get(1);
                System.out.println(str);
            }
        }
    }

    運(yùn)行Sample,main函數(shù)執(zhí)行的結(jié)果是輸出兩行,第一行為aaa,第二行為null。
    posted @ 2007-04-27 20:04 溫少的日志 閱讀(2021) | 評(píng)論 (2)編輯 收藏
     
    china-pub購書網(wǎng)址:http://www.china-pub.com/computers/common/info.asp?id=34017

    1、總體感受
    a) 這本書主要介紹的是intel平臺(tái)下的多核程序設(shè)計(jì)技術(shù),Windows介紹較多,Linux介紹較少,Java更少。作者是Intel公司的平臺(tái)架構(gòu)師,我們知道wintel聯(lián)盟,書中的內(nèi)容如此分布也是正常。
    b) 此書讓我懂得了很多硬件方面的并行知識(shí)。
    c) 此書介紹Windows API中和并發(fā)相關(guān)的部分,很詳盡,比Jeffrey Richter的《Windows核心編成》有深度多了,也精辟多了。顯然《多核程序設(shè)計(jì)》作者屬于有經(jīng)驗(yàn)的工程師,Jeffrey Richter只是一個(gè)寫手,兩者沒有可比性。不過這方面的知識(shí)偶早已涉獵,當(dāng)作復(fù)習(xí)一遍罷了。
    d) 此書偏向底層,硬件和操作系統(tǒng)層面。更高層面的技術(shù)介紹較少。
    e) 第一次了解OpenMP技術(shù)的一些細(xì)節(jié)。以前只聽說,也沒查過任何相關(guān)資料,在此書中看到了相關(guān)部分,挺有意思的,感覺那些語法很有趣。Herb Sutter也是要在語法方面動(dòng)手。反正我在有了一個(gè)粗淺認(rèn)識(shí)之后,覺得很有意思。

    -------------------------

    2、并發(fā)流程控制
    Fence
    在Java 中對(duì)應(yīng)的是java.util.concurrent.CountDownLatch。最初接觸CountDownLatch的時(shí)候,由于其實(shí)現(xiàn)很簡(jiǎn)單, 當(dāng)時(shí)覺得是一個(gè)可有可無的工具類。但后來在不同的場(chǎng)景多次使用,發(fā)現(xiàn)很有用。在此書中再次發(fā)現(xiàn)類似的Fence,用于在共享存儲(chǔ)多處理器或者多核環(huán)境中, 確保存儲(chǔ)操作的一致性。我猜這屬于業(yè)界并發(fā)流控制的典型手段了。


    Barrier
    在Java中對(duì)應(yīng)的是java.util.concurrent.CyclicBarrier。在應(yīng)用程序中,一個(gè)場(chǎng)景就是和定時(shí)器結(jié)合使用,countDown、await、reset,做定時(shí)定量批量處理。
    我猜這也屬于業(yè)界并發(fā)流程控制的典型手段了。

    (CountDownLatch和CycliBarrier的實(shí)現(xiàn)代碼都很簡(jiǎn)單,但很有用,他們都屬于并發(fā)流程控制的典型手段)

    -------------------------

    3、非阻塞算法
    InterLocked在Java中對(duì)應(yīng)的是java.util.concurrent.atomic.xxx
    書中提到了cache行乒乓球現(xiàn)象導(dǎo)致的性能問題,提高了非阻塞算法的復(fù)雜性問題。

    關(guān)于性能問題,developerworks上有一片文章,有測(cè)試數(shù)據(jù):
    《Java 理論與實(shí)踐: 流行的原子》 (http://www.ibm.com/developerworks/cn/java/j-jtp11234/index.html)
    文章中的測(cè)試數(shù)據(jù)表明,直接使用atomic在1個(gè)和2個(gè)處理器時(shí)是最好的,4個(gè)處理器以上,使用java.util.concurrent.locks.ReentrantLock性能更好。

    java.util.concurrent包,提供了很多高級(jí)的概念,隱藏了非阻塞算法帶來的復(fù)雜度,其底層框架達(dá)到了最佳性能。

    -------------------------

    4、任務(wù)分解、數(shù)據(jù)分解以及數(shù)據(jù)流分解
    此書中明確提出了這三個(gè)概念,很有用,讓我在這方面的知識(shí)概念清晰化了。

    任務(wù)分解
    Java 中的Executor,提供了任務(wù)分解的手段和模式。任務(wù)分解提交給Executor執(zhí)行。java.util.concurrent中提供了 Future,用于任務(wù)提交者和Executor之間的協(xié)調(diào)。Future是一種很好的手段,在很多涉及并發(fā)的庫都提供。例如C++網(wǎng)絡(luò)并發(fā)庫中提供了 Future,Herb Sutter要在Visual C++中引入Future。

    數(shù)據(jù)分解
    數(shù)據(jù)分解的手段很多也很常見。 Java中,提供了一種高級(jí)的數(shù)據(jù)分解協(xié)同模式j(luò)ava.util.concurrent.Exchanger這個(gè)類。早在Java SE 5.0時(shí),Exchanger只支持2Parties,Java SE 6.0支持n parties。偶想象過一些很酷的應(yīng)用場(chǎng)景,寫過模擬測(cè)試,但一直沒有機(jī)會(huì)用于實(shí)際開發(fā)中。

    數(shù)據(jù)流分解
    書中提到了眾多周知的producer/consumer問題。
    其實(shí)java.util.concurrent.Exchanger類,既有數(shù)據(jù)分解,又有數(shù)據(jù)流分解,exchanger中的producer和consumer的角色會(huì)互換的,很有意思。

    -------------------------

    5、作為Java程序員的思考
    Java SE 5.0之后,提供了util.concurrent包,功能齊全,性能卓越,非常優(yōu)秀。從此書來看,業(yè)界流行的流程控制手段和并發(fā)程序設(shè)計(jì)方法一個(gè)不落。我們應(yīng)該感謝偉大的Doug Lea,他為我們帶了一個(gè)如此完美的并發(fā)庫!
    posted @ 2007-04-26 07:08 溫少的日志 閱讀(3288) | 評(píng)論 (0)編輯 收藏
     

    一旦方案想清楚,剩余部分的工作效率瓶頸就在于你的手速了。最近一直看起點(diǎn)中文網(wǎng)上的《師士傳說》,主角葉重一個(gè)強(qiáng)項(xiàng)就是手速。

    最基本的就是盲打。不會(huì)盲打的通常屬于“編碼低能兒”。身邊也有不會(huì)盲打的朋友,他們通常都有一個(gè)問題,就是眼高手低,說說還行,動(dòng)手就不行。當(dāng)然他們能夠在IT研發(fā)領(lǐng)域還混得很好,是因?yàn)樵谄渌矫鎿碛袃?yōu)秀的能力。

    熟練掌握快捷鍵是關(guān)鍵。鍵盤和鼠標(biāo)之間通常有較大的距離,手經(jīng)常在鍵盤和鼠標(biāo)之間移動(dòng),會(huì)降低效率,也容易導(dǎo)致疲勞,用鼠標(biāo)過多,也容易導(dǎo)致齷齪的鼠標(biāo)手。解決這個(gè)問題的辦法,就是純鍵盤操作,其實(shí)很多IDE的快捷鍵功能強(qiáng)大,足以讓你純鍵盤操作,高效率編碼。

    我比較熟悉的IDE是Eclipse,就以Eclispse來說吧。

    Eclipse的keys列表中,屬于Eclipse本身有180多個(gè)快捷鍵,要提高編碼速度,就應(yīng)該熟練使用其中絕大多數(shù)。

    練習(xí)的辦法:
    1、在Windows/Preferences/General/keys中,使用Export,把快捷鍵導(dǎo)出,導(dǎo)出的格式是csv格式,Windows下可以用Excel直接打開,Linux下可以用OpenOffice打開,打開時(shí)選擇分隔符為“,”。

    2、挨個(gè)練習(xí)使用。每天練習(xí)一部分,反復(fù)練習(xí),堅(jiān)持一段時(shí)間。

    3、開始的時(shí)候,把鼠標(biāo)放到一個(gè)不方便使用的角落,盡量不要讓自己用鼠標(biāo)。

    4、快捷鍵的組合使用需要加強(qiáng)訓(xùn)練。在不同場(chǎng)景下,認(rèn)真考慮用怎樣的組合快捷鍵最高效。

    如此堅(jiān)持一段時(shí)間之后,編碼的過程會(huì)很流暢,速度就會(huì)大大提高。



    posted @ 2007-04-25 07:41 溫少的日志 閱讀(3222) | 評(píng)論 (25)編輯 收藏
     

    這是一個(gè)很老的問題了,經(jīng)常在論壇上看到,很多人也寫了相關(guān)的文章。我在這方面擁有較多的經(jīng)驗(yàn),我也談一下我的看法吧。

    我曾經(jīng)實(shí)現(xiàn)過金蝶EAS BOS的多數(shù)據(jù)支持引擎,腳本引擎,也作過O-R Mapping的預(yù)研工作,曾經(jīng)對(duì)多個(gè)O-R Mapping產(chǎn)品做過研究。

    C++、Java、C#都源自Algol,這系列語言也稱為Imperative語言,中文翻譯為命令式語言。命令式語言建立在馮*諾依曼體系結(jié)構(gòu)上,程序員必須處理變量管理、變量復(fù)制。這樣的結(jié)果是增加了執(zhí)行的效率,但帶來了程序開發(fā)的艱苦。

    LISP、Schema、Haskell等語言屬于函數(shù)式語言,函數(shù)式語言基于數(shù)學(xué)函數(shù),不使用變量或者賦值語句產(chǎn)生結(jié)果,使用函數(shù)的應(yīng)用、條件表示和遞歸作為執(zhí)行控制。函數(shù)式語言是更高級(jí)的程序設(shè)計(jì)語言,和命令式語言相比,編寫更少的代碼,更高的開發(fā)效率,這是函數(shù)式語言的明確有點(diǎn)。很多編程技術(shù)都首先應(yīng)用于函數(shù)式語言,例如范型、垃圾收集等。很多函數(shù)式語言都增加了一些命令式語言的特征,增加效率和易用性。

    SQL語言是一個(gè)領(lǐng)域?qū)S谜Z言,專門用于處理關(guān)系數(shù)據(jù)。他具備一些函數(shù)式語言的特征,在處理關(guān)系數(shù)據(jù)方面非常直觀和簡(jiǎn)介。在處理選擇、投影、聚合、排序等等操作方面,顯然比在Java或者C#中要方便得多。SQL也是易學(xué)易用。很多非程序員都掌握SQL,在金蝶,大多需求人員都熟練掌握SQL。SQL的解釋需要損耗一定的性能,在對(duì)性能極端要求的情況下,通常不使用關(guān)系數(shù)據(jù)庫。例如Google Account采用Berkeley DB等。

    現(xiàn)在關(guān)系數(shù)據(jù)庫已經(jīng)發(fā)展很成熟,數(shù)據(jù)庫的一些技術(shù)發(fā)展得很好,包括事務(wù)等,其中一些從數(shù)據(jù)庫中發(fā)展起來的技術(shù),還應(yīng)用到操作系統(tǒng)中了。在前些年面向?qū)ο蠹夹g(shù)狂熱的時(shí)候,作了很多面向?qū)ο髷?shù)據(jù)庫的研究,但是都沒有取得較大的成功。在主流的關(guān)系數(shù)據(jù)庫中,大多都包括了面向?qū)ο蟮闹С郑鏞racle、Sybase,都具備了很豐富的面向?qū)ο蠊δ埽呛苌偃斡谩?br>
    現(xiàn)在有人跟我說起db4o這樣的數(shù)據(jù)庫,我認(rèn)為db4o不會(huì)取得成功,因?yàn)樗阱e(cuò)誤的方向發(fā)展。

    現(xiàn)在關(guān)系數(shù)據(jù)庫最流行,最流行的應(yīng)用開發(fā)語言包括Java、C#等,都是面向?qū)ο竺钍秸Z言。開發(fā)語言需要訪問關(guān)系數(shù)據(jù)庫,需要轉(zhuǎn)換,轉(zhuǎn)換的過程比較繁瑣,于是就誕生了O-R Mapping技術(shù)。這是一種妥協(xié)的結(jié)果,面向?qū)ο蠹夹g(shù)在數(shù)據(jù)庫領(lǐng)域無法取得成功,在面向?qū)ο箝_發(fā)語言中,就需要一種對(duì)象-關(guān)系映射技術(shù)。我相信,這種妥協(xié)產(chǎn)生的技術(shù),會(huì)越來越流行。

    我也認(rèn)為,這是一個(gè)正確的選擇。就如高級(jí)語言不會(huì)嘗試取代匯編,無論高級(jí)語言有多好,最多在其上增加抽象層。例如Java使用bytecode、C#使用IL這樣,使用一種抽象層,而不是嘗試取代匯編。

    O-R Mapping技術(shù)除了簡(jiǎn)單映射之外,需要一種OQL,混合SQL和面向?qū)ο筇卣鳎峁┯成浞奖愕耐瑫r(shí),保留關(guān)系數(shù)據(jù)庫提供的強(qiáng)大功能。例如聚合、排序等關(guān)系運(yùn)算必須在OQL中提供。由于程序中的返回結(jié)果,有時(shí)不需要映射成對(duì)象,所以O(shè)QL必須提供另外一種功能,數(shù)據(jù)查詢。很多O-R Mappping產(chǎn)品都提供了基于對(duì)象的OQL和基于數(shù)據(jù)的OQL。

    這導(dǎo)致包括三個(gè)部分:
    1、應(yīng)用程序使用OQL
    2、O-R Mapping解釋或者編譯OQL
    3、對(duì)象數(shù)據(jù)庫負(fù)責(zé)數(shù)據(jù)處理

    如果O-R Mapping使用解釋的方式處理OQL,則會(huì)包括產(chǎn)生SQL、組裝對(duì)象等操作。效率通常都不會(huì)很好,現(xiàn)在的O-R Mapping產(chǎn)品基本都是基于解釋的方式處理。

    如果O-R Mapping使用編譯的方式,可以優(yōu)化產(chǎn)生SQL,動(dòng)態(tài)創(chuàng)建SQL存儲(chǔ)過程,減少SQL交互的過程,能夠獲得很好的性能,可以做到比絕
    大多數(shù)人直接使用SQL性能都要好。我曾經(jīng)做過一個(gè)實(shí)驗(yàn)性的實(shí)現(xiàn),取得很好的效果,可惜由于種種原因,沒有繼續(xù)下去。

    我認(rèn)為,下一代的O-R Mapping產(chǎn)品,都將會(huì)采用編譯的方式,因?yàn)樵诤芏嗲樾蜗拢貏e是復(fù)雜對(duì)象的處理方面,可以有大幅度的性能提升,在某些場(chǎng)景下,可以數(shù)倍甚至數(shù)十倍的性能提升。

    一直不是很看好Hibernate,因?yàn)槠渲饕髡遟avin對(duì)編譯技術(shù)不了解,2.x版本的HQL語法很搞笑,實(shí)現(xiàn)也是很搞笑的,簡(jiǎn)單的文本替換,看到讓人目瞪口呆。3.0之后加入了HQL的AST(抽象語法樹),但這不是他本人的做的,其他愛好者加入進(jìn)來,3.1還是沒有很好融合進(jìn)來。之后的版本我就沒有繼續(xù)關(guān)注了。

    我覺得O-R Mapping完全就是一種編譯技術(shù),不懂編譯技術(shù)的人去作這件事清總會(huì)有些不妥。這不單是Hibernate的問題,也是其他O-R Mapping產(chǎn)品的問題。


    我的觀點(diǎn):
    1、Java、C#、C++等語言在處理關(guān)系數(shù)據(jù)方面沒有優(yōu)勢(shì)。SQL是關(guān)系數(shù)據(jù)處理的領(lǐng)域?qū)S谜Z言(DSL),更適合處理關(guān)系數(shù)據(jù),提供強(qiáng)大的功能。
    2、關(guān)系數(shù)據(jù)是主流,希望應(yīng)用開發(fā)人員使用O-R Mapping,而不懂關(guān)系數(shù)據(jù)庫,這是不現(xiàn)實(shí)的。
    3、O-R Mapping技術(shù)還有很大發(fā)展空間,以后在功能、性能等方面都會(huì)有重大提升,最終成熟。


    溫少 2007-04-23 08:18 發(fā)表評(píng)論

    文章來源:http://www.cnblogs.com/jobs/archive/2007/04/23/723297.html
    posted @ 2007-04-23 08:23 溫少的日志 閱讀(1174) | 評(píng)論 (2)編輯 收藏
     

    在操作系統(tǒng)中,有兩種不同的方法提供線程支持:用戶層的用戶線程,或內(nèi)核層的內(nèi)核線程。

    其中用戶線程在內(nèi)核之上支持,并在用戶層通過線程庫來實(shí)現(xiàn)。不需要用戶態(tài)/核心態(tài)切換,速度快。操作系統(tǒng)內(nèi)核不知道多線程的存在,因此一個(gè)線程阻塞將使得整個(gè)進(jìn)程(包括它的所有線程)阻塞。由于這里的處理器時(shí)間片分配是以進(jìn)程為基本單位,所以每個(gè)線程執(zhí)行的時(shí)間相對(duì)減少。

    內(nèi)核線程由操作系統(tǒng)直接支持。由操作系統(tǒng)內(nèi)核創(chuàng)建、調(diào)度和管理。內(nèi)核維護(hù)進(jìn)程及線程的上下文信息以及線程切換。一個(gè)內(nèi)核線程由于I/O操作而阻塞,不會(huì)影響其它線程的運(yùn)行。

    Java線程的實(shí)現(xiàn)是怎樣的呢?我們通過SUN Java 6的源碼了解其在Windows和Linux下的實(shí)現(xiàn)。

    在Windows下的實(shí)現(xiàn),os_win32.cpp中
    // Allocate and initialize a new OSThread
    bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
      unsigned thread_id;

      
    // Allocate the OSThread object
      OSThread* osthread = new OSThread(NULL, NULL);
      
    if (osthread == NULL) {
        
    return false;
      }

      
    // Initial state is ALLOCATED but not INITIALIZED
      {
        MutexLockerEx ml(thread
    ->SR_lock(), Mutex::_no_safepoint_check_flag);
        osthread
    ->set_state(ALLOCATED);
      }
      
      
    // Initialize support for Java interrupts
      HANDLE interrupt_event = CreateEvent(NULL, truefalse, NULL);
      
    if (interrupt_event == NULL) {
        delete osthread;
        
    return NULL;
      }
      osthread
    ->set_interrupt_event(interrupt_event);
      osthread
    ->set_interrupted(false);
      
      thread
    ->set_osthread(osthread);
      
      
    if (stack_size == 0) {
        
    switch (thr_type) {
        
    case os::java_thread:
          
    // Java threads use ThreadStackSize which default value can be changed with the flag -Xss
          if (JavaThread::stack_size_at_create() > 0)
            stack_size 
    = JavaThread::stack_size_at_create();
          
    break;
        
    case os::compiler_thread:
          
    if (CompilerThreadStackSize > 0) {
            stack_size 
    = (size_t)(CompilerThreadStackSize * K);
            
    break;
          } 
    // else fall through:
            
    // use VMThreadStackSize if CompilerThreadStackSize is not defined
        case os::vm_thread:
        
    case os::pgc_thread:
        
    case os::cgc_thread:
        
    case os::watcher_thread:
          
    if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
          
    break;
        }
      }

      
    // Create the Win32 thread
      
    //
      
    // Contrary to what MSDN document says, "stack_size" in _beginthreadex()
      
    // does not specify stack size. Instead, it specifies the size of
      
    // initially committed space. The stack size is determined by
      
    // PE header in the executable. If the committed "stack_size" is larger
      
    // than default value in the PE header, the stack is rounded up to the
      
    // nearest multiple of 1MB. For example if the launcher has default
      
    // stack size of 320k, specifying any size less than 320k does not
      
    // affect the actual stack size at all, it only affects the initial
      
    // commitment. On the other hand, specifying 'stack_size' larger than
      
    // default value may cause significant increase in memory usage, because
      
    // not only the stack space will be rounded up to MB, but also the
      
    // entire space is committed upfront.
      
    //
      
    // Finally Windows XP added a new flag 'STACK_SIZE_PARAM_IS_A_RESERVATION'
      
    // for CreateThread() that can treat 'stack_size' as stack size. However we
      
    // are not supposed to call CreateThread() directly according to MSDN
      
    // document because JVM uses C runtime library. The good news is that the
      
    // flag appears to work with _beginthredex() as well.

    #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
    #define STACK_SIZE_PARAM_IS_A_RESERVATION  (0x10000)
    #endif

      HANDLE thread_handle 
    =
        (HANDLE)_beginthreadex(NULL,
                               (unsigned)stack_size,
                               (unsigned (__stdcall 
    *)(void*)) java_start,
                               thread,
                               CREATE_SUSPENDED 
    | STACK_SIZE_PARAM_IS_A_RESERVATION,
                               
    &thread_id);
      
    if (thread_handle == NULL) {
        
    // perhaps STACK_SIZE_PARAM_IS_A_RESERVATION is not supported, try again
        
    // without the flag.
        thread_handle =
        (HANDLE)_beginthreadex(NULL,
                               (unsigned)stack_size,
                               (unsigned (__stdcall 
    *)(void*)) java_start,
                               thread,
                               CREATE_SUSPENDED,
                               
    &thread_id);
      }
      
    if (thread_handle == NULL) {
        
    // Need to clean up stuff we've allocated so far
        CloseHandle(osthread->interrupt_event());
        thread
    ->set_osthread(NULL);
        delete osthread;
        
    return NULL;
      }
      
      Atomic::inc_ptr((intptr_t
    *)&os::win32::_os_thread_count);

      
    // Store info on the Win32 thread into the OSThread
      osthread->set_thread_handle(thread_handle);
      osthread
    ->set_thread_id(thread_id);

      
    // Initial thread state is INITIALIZED, not SUSPENDED
      {
        MutexLockerEx ml(thread
    ->SR_lock(), Mutex::_no_safepoint_check_flag);
        osthread
    ->set_state(INITIALIZED);
      }

      
    // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain
      return true;
    }

    可以看出,SUN JVM在Windows下的實(shí)現(xiàn),使用_beginthreadex來創(chuàng)建線程,注釋中也說明了為什么不用“Window編程書籍推薦使用”的CreateThread函數(shù)。由此看出,Java線程在Window下的實(shí)現(xiàn)是使用內(nèi)核線程。

    而在Linux下又是怎樣的呢?

    在os_linux.cpp文件中的代碼摘錄如下:

    # include <pthread.h>

    bool
     os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
      assert(thread
    ->osthread() == NULL, "caller responsible");

      
    // Allocate the OSThread object
      OSThread* osthread = new OSThread(NULL, NULL);
      
    if (osthread == NULL) {
        
    return false;
      }

      
    // set the correct thread state
      osthread->set_thread_type(thr_type);

      
    // Initial state is ALLOCATED but not INITIALIZED
      osthread->set_state(ALLOCATED);

      thread
    ->set_osthread(osthread);

      
    // init thread attributes
      pthread_attr_t attr;
      pthread_attr_init(
    &attr);
      pthread_attr_setdetachstate(
    &attr, PTHREAD_CREATE_DETACHED);

      
    // stack size
      if (os::Linux::supports_variable_stack_size()) {
        
    // calculate stack size if it's not specified by caller
        if (stack_size == 0) {
          stack_size 
    = os::Linux::default_stack_size(thr_type);

          
    switch (thr_type) {
          
    case os::java_thread:
            
    // Java threads use ThreadStackSize which default value can be changed with the flag -Xss
            if (JavaThread::stack_size_at_create() > 0) stack_size = JavaThread::stack_size_at_create();
            
    break;
          
    case os::compiler_thread:
            
    if (CompilerThreadStackSize > 0) {
              stack_size 
    = (size_t)(CompilerThreadStackSize * K);
              
    break;
            } 
    // else fall through:
              
    // use VMThreadStackSize if CompilerThreadStackSize is not defined
          case os::vm_thread: 
          
    case os::pgc_thread: 
          
    case os::cgc_thread: 
          
    case os::watcher_thread: 
            
    if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
            
    break;
          }
        }

        stack_size 
    = MAX2(stack_size, os::Linux::min_stack_allowed);
        pthread_attr_setstacksize(
    &attr, stack_size);
      } 
    else {
        
    // let pthread_create() pick the default value.
      }

      
    // glibc guard page
      pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));

      ThreadState state;

      {
        
    // Serialize thread creation if we are running with fixed stack LinuxThreads
        bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
        
    if (lock) {
          os::Linux::createThread_lock()
    ->lock_without_safepoint_check();
        }

        pthread_t tid;
        
    int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);

        pthread_attr_destroy(
    &attr);

        
    if (ret != 0) {
          
    if (PrintMiscellaneous && (Verbose || WizardMode)) {
            perror(
    "pthread_create()");
          }
          
    // Need to clean up stuff we've allocated so far
          thread->set_osthread(NULL);
          delete osthread;
          
    if (lock) os::Linux::createThread_lock()->unlock();
          
    return false;
        }

        
    // Store pthread info into the OSThread
        osthread->set_pthread_id(tid);

        
    // Wait until child thread is either initialized or aborted
        {
          Monitor
    * sync_with_child = osthread->startThread_lock();
          MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
          
    while ((state = osthread->get_state()) == ALLOCATED) {
            sync_with_child
    ->wait(Mutex::_no_safepoint_check_flag);
          }
        }

        
    if (lock) {
          os::Linux::createThread_lock()
    ->unlock();
        }
      }

      
    // Aborted due to thread limit being reached
      if (state == ZOMBIE) {
          thread
    ->set_osthread(NULL);
          delete osthread;
          
    return false;
      }

      
    // The thread is returned suspended (in state INITIALIZED),
      
    // and is started higher up in the call chain
      assert(state == INITIALIZED, "race condition");
      
    return true;
    }

    Java在Linux下的線程的創(chuàng)建,使用了pthread線程庫,而pthread就是一個(gè)用戶線程庫,因此結(jié)論是,Java在Linux下是使用用戶線程實(shí)現(xiàn)的。





    溫少 2007-04-18 05:28 發(fā)表評(píng)論
    posted @ 2007-04-18 05:28 溫少的日志 閱讀(943) | 評(píng)論 (4)編輯 收藏
     

    MessageDigest的選擇好多,包括MD2、MD4、MD5、SHA-1、SHA-256、RIPEMD128、RIPEMD160等等。我們?nèi)绾芜x擇呢?

    選擇考慮在兩個(gè)方面:安全、速度。

    MD2很安全,但是速度極慢,一般不用。

    速度方面,最快的是MD4,MD5比SHA-1快

    速度排名:MD4 > MD5 > RIPEMD-128 > SHA-1 > REPEMD-160

    按照《應(yīng)用密碼學(xué)手冊(cè)》提供的表格數(shù)據(jù)為:
    MD4 長(zhǎng)度 128 相對(duì)速度 1
    MD5 長(zhǎng)度 128 相對(duì)速度 0.68
    REPEMD-128 長(zhǎng)度 128 相對(duì)速度 0.39
    SHA-1 長(zhǎng)度 160 相對(duì)速度 0.29
    REPEMD-160 長(zhǎng)度 160 相對(duì)速度 0.24

    我親自測(cè)試的結(jié)果和《應(yīng)用密碼學(xué)手冊(cè)》提供的數(shù)據(jù)接近。

    MD4已經(jīng)很早證明有缺陷,很少使用,最流行的是MD5和SHA-1,但MD5和SHA1也被王小云找到碰撞,證實(shí)不安全。

    傳說SHA-1比MD5要安全,但是SHA-1有美國國家安全局的背景,有人懷疑這個(gè)算法背后有不可告人的秘密,我也是陰謀論者之一,傾向選擇MD5而不是SHA-1。王小云找到SHA-1碰撞之后,可以說傳說的謠言破滅了,而且MD5速度要比SHA-1快差不多一倍,沒有什么理由選擇SHA-1。

    ----------------------------------

    在Java的現(xiàn)實(shí)環(huán)境中是怎樣?

    在SUN的JCE實(shí)現(xiàn)中,只提供了MD2、MD5、SHA-1,SHA-256等常用的MessageDigest算法。

    開源的JCE實(shí)現(xiàn)bouncycastle則提供了眾多的實(shí)現(xiàn),包括MD整個(gè)系列,SHA整個(gè)系列,RIPEMD整個(gè)系列。

    很多的開源項(xiàng)目都帶一個(gè)bcprov-jdk14.jar的包,可以說bouncycastle應(yīng)用很廣泛。SUN公司的一些項(xiàng)目也用了bouncycastle,例如JXTA。

    但實(shí)際上,SUN的實(shí)現(xiàn)包括了MD4,但你需要這樣使用:
    MessageDigest md = sun.security.provider.MD4.getInstance();


    但是,JDK帶實(shí)現(xiàn)性能要比bouncycastle性能好得多,相差速度通常超過一倍以上,我測(cè)試過MD5、SHA1和MD4,其性能差別都是類似,一倍多。

    比較的結(jié)論:
    bouncycastle開源免費(fèi),提供算法多,但速度較慢
    SUN JCE提供的實(shí)現(xiàn),包括了流行常用算法,速度很快,同類型算法比bouncycastle要快一倍以上。

    ----------------------------------

    結(jié)論:

    又要安全又要速度,選擇MD5
    追求安全,不在意速度,相信傳說,不相信陰謀論,選擇SHA系列
    追求速度,安全次之,可以選擇MD4。

    ----------------------------------
    現(xiàn)實(shí)例子:
    emule采用MD4和SHA-1兩種結(jié)合使用
    apache之類的技術(shù)網(wǎng)站,提供下載的文件,同時(shí)提供一個(gè)校驗(yàn)文件.md5



    溫少 2007-04-14 17:02 發(fā)表評(píng)論
    posted @ 2007-04-14 17:02 溫少的日志 閱讀(491) | 評(píng)論 (0)編輯 收藏
     
    JSR-000203 More New I/O APIs for the Java Platform - Early Draft Review

    http://jcp.org/aboutJava/communityprocess/edr/jsr203/index.html


    API的Early Draft Review出來了,就意味很快就要真的出來啦!!

    以下是其文檔的一個(gè)Sample

     static class IOTransaction {
          
    public ByteBuffer buffer() {  }
          
    public long position() {  }
          
    public long updatePosition(int transferred) {  }
      }

      
    static class WriteHandler implements CompletionHandler<Integer> {

          
    public WriteHandler(AsynchronousFileChannel ch) {  }

          
    private AsynchronousFileChannel channel() {  }

          
    public void completed(IoFuture<Integer> result) {
              
    int bytesTransferred;
              
    try {
                  bytesTransferred 
    = result.getNow();
              } 
    catch (ExecutionException x) {  }
     
              IOTransaction transaction 
    = (IOTransaction)result.attachment();   
              ByteBuffer buffer 
    = transaction.buffer();
              
    if (buffer.remaining() > 0) {
                  
    long position = transaction.updatePosition(bytesTransferred);
                  channel().write(buffer, position, transaction, 
    this);
              }
          }
      }

      FileReference file 
    = 
      List
    <IOTransaction> transactionList = 
      
      AsynchronousFileChannel ch 
    = AsynchronousFileChannel.open(file, OpenFlag.WRITE);

      WriteHandler handler 
    = new WriteHandler(ch);

      
    for (IOTransaction transaction: transactionList) {
          
    // use the transaction as the attachment
          ch.write(transaction.buffer(), transaction.position(), transaction, handler);
      }


    就是我最近很需要的東西,一個(gè)異步I/O的實(shí)現(xiàn),十分期待中!!



    溫少 2007-04-14 12:15 發(fā)表評(píng)論
    posted @ 2007-04-14 12:15 溫少的日志 閱讀(264) | 評(píng)論 (0)編輯 收藏
     

    不是使用每連接一線程的技術(shù),而是使用多路復(fù)用技術(shù)。

    作了一個(gè)分配算法。第一個(gè)HTTP Request返回取得ContentLength之后,如果使用多個(gè)連接下載,則需要一個(gè)分配算法,分配每個(gè)Request所對(duì)應(yīng)的Range。分配的部分可能是一個(gè)連續(xù)的塊,例如bytes=100-999,也可能是一些碎塊,例如bytes=500-600,700-800,850-999。為此,我做了一個(gè)數(shù)據(jù)結(jié)構(gòu),其提供的功能類似java.util.BitSet,也支持and、or等操作。

    實(shí)現(xiàn)了對(duì)ContentType為multipart/bytes的HTTP Message Body的解釋。如果發(fā)送HTTP Request,Range為多個(gè)不連續(xù)的部分,返回的HTTP Message,就會(huì)是multipart,每個(gè)part都會(huì)包括一個(gè)Head和一個(gè)Body,需要一個(gè)解析器。

    下一步就是把HTTP下載加入P2P下載中!


    溫少 2007-04-12 01:37 發(fā)表評(píng)論
    posted @ 2007-04-12 01:37 溫少的日志 閱讀(380) | 評(píng)論 (0)編輯 收藏
     

    最近編碼更流暢了。原因包括:

    1) 絕大多數(shù)時(shí)候純鍵盤操作,Eclipse 200多個(gè)快捷鍵,我熟練使用絕大部分,編碼的過程,如同行云流水般。

    2)掌握了更多的解決問題的辦法,有了更廣的知識(shí)面,編碼時(shí),信手拈來。最近一年里,掌握了很多知識(shí),包括并發(fā)、網(wǎng)絡(luò)、操作系統(tǒng)等等方面的知識(shí)。

    3)組織代碼的能力更強(qiáng)了,最近對(duì)于大型復(fù)雜的程序,組織代碼的能力更強(qiáng)了,組織程序的能力包括,更好的結(jié)構(gòu),更好的擴(kuò)展性,可測(cè)試性,可管理性等等。
      a) 在編碼的過程中,使得更多的模塊可以單獨(dú)于整個(gè)環(huán)境獨(dú)立測(cè)試
      b) 精心處理過的LOG,使得代碼更容易跟蹤,排錯(cuò)。
      c) 復(fù)雜的模塊,附帶監(jiān)控管理界面,使得排錯(cuò)和優(yōu)化都更為方便。
      d) 使用制作狀態(tài)轉(zhuǎn)換表的手段,清晰化復(fù)雜的狀態(tài)處理。在前些年設(shè)計(jì)/實(shí)現(xiàn)工作流引擎時(shí),就開始使用狀態(tài)轉(zhuǎn)換表描述狀態(tài)機(jī),但現(xiàn)在面臨的狀態(tài)機(jī)復(fù)雜。




    溫少 2007-03-31 02:42 發(fā)表評(píng)論
    posted @ 2007-03-31 02:42 溫少的日志 閱讀(260) | 評(píng)論 (0)編輯 收藏
     

    貼圖的實(shí)現(xiàn)方式為:

    1、把剪切板中的圖片存在本地的SendingImages目錄,存放的格式使用PNG,當(dāng)然可以其他格式,但是PNG格式更小。
    2、使用MD5算法產(chǎn)生一個(gè)ImageID。當(dāng)然可以使用SHA1等其他算法
    3、把imageID發(fā)送remote peer
    4、當(dāng)remote peer收到imageID時(shí),檢查本地ReceivedImage目錄,如果已經(jīng)存在,顯示圖片,不存在則發(fā)送一個(gè)RequestImage請(qǐng)求,并在聊天記錄中顯示一個(gè)等待信息(為一個(gè)GIF動(dòng)畫)。
    5、本地Peer收到RequestImage請(qǐng)求之后,發(fā)送圖片數(shù)據(jù)。如果圖片大于64K,則分塊發(fā)送。
    6、remote peer收到圖像數(shù)據(jù)之后,進(jìn)行校驗(yàn),看是否正確。
    7、校驗(yàn)通過后,把圖片在聊天面板上顯示(替換等待圖片)


    預(yù)定義表情的實(shí)現(xiàn)很簡(jiǎn)單,自定義表情的實(shí)現(xiàn)和貼圖實(shí)現(xiàn)一致,只是少了從剪貼板保存圖片的過程。



    溫少 2007-03-30 22:01 發(fā)表評(píng)論
    posted @ 2007-03-30 22:01 溫少的日志 閱讀(226) | 評(píng)論 (0)編輯 收藏
     
    上一篇博客寫了我一些關(guān)于P2P下載以及平臺(tái)的思考,有這樣的思考,是因?yàn)槲艺谧鲆患@樣的事情。

    我介紹一下我正在做的事情吧:

    1、基于JXTA,我崇拜Bill Joy,學(xué)習(xí)JXTA就是因?yàn)槲页绨菟笥X得這個(gè)技術(shù)很棒。但是JXTA存在一些用戶不友好的地方,包括JXTA的ConfigDialog和DialogAuthenticator是十分用戶不友好的,我重寫了這些部分。雖然是一些無關(guān)痛癢的地方,但是可以改變用戶體驗(yàn),提高用戶友好性。

    2、簡(jiǎn)單的插件機(jī)制,我做了一個(gè)簡(jiǎn)單的插件系統(tǒng),Application啟動(dòng)之后挨個(gè)裝載服務(wù),UI也是服務(wù)之一,UI也是基于插件的,在微內(nèi)核框架流行的今天,使用一個(gè)簡(jiǎn)單的插件機(jī)制似乎不是太好,等過一段時(shí)間之后考慮使用osgi替代之。

    3、提供了兩個(gè)功能,聊天和文件共享下載。這兩個(gè)功能分別表現(xiàn)為兩個(gè)JXTA的Service。

    4、聊天功能。目前還比較簡(jiǎn)單,只實(shí)現(xiàn)了不帶格式的文本聊天,但是我隨后會(huì)加入帶格式的文本聊天,也將會(huì)加入類似騰訊QQ那樣的貼圖支持,自定義表情支持,騰訊QQ的實(shí)現(xiàn)很巧妙,但并不困難。四月初的版本就有可能實(shí)現(xiàn)之。

    5、共享和下載。目前實(shí)現(xiàn)了文件和文件夾的共享。其中包括了高級(jí)智能錯(cuò)誤檢測(cè)(AICH)等。傳輸協(xié)議參考了BT和emule的協(xié)議。在界面中還實(shí)現(xiàn)對(duì)DragAndDrop支持,從Windows Explore中拖一個(gè)文件到目錄共享的面板,即開始共享該文件。

    6、存儲(chǔ)信息采用apache的Derby數(shù)據(jù)庫。我很喜歡Berkeley DB,Berkely DB高效簡(jiǎn)潔,但是License不開放。我最終還是采用Derby了,采用Derby將會(huì)帶來一系列好處,SQL支持、JDBC支持等等,License無限制等等。擴(kuò)展的應(yīng)用基于其上也十分方便。由于我曾經(jīng)開發(fā)過多數(shù)據(jù)庫支持引擎KSQL,在KSQL上增加支持Derby的翻譯是很容易的事情。如此一來,可能存儲(chǔ)引擎部分,將有可能擴(kuò)展到KSQL目前所支持的多種數(shù)據(jù)庫,包括嚴(yán)格測(cè)試過的Oracle、DB2、MS SQL Server,還有經(jīng)過簡(jiǎn)單測(cè)試支持Sybase、PostgreSQL、MySQL。

    7、最近的JXTA Java SE 2.5版本,使用了nio來管理連接,也就說,使用了多路復(fù)用的技術(shù),使得每個(gè)Peer創(chuàng)建大量連接成為可能,例如Windows下默認(rèn)最大的多路復(fù)用支持1024個(gè)連接。而Linux下,java nio是使用epoll實(shí)現(xiàn)的,并發(fā)性能將更好,這對(duì)于聚合點(diǎn)來說很重要。普通的Peer部署在Linux下可能較少,但是聚合點(diǎn)部署在Linux完全是可能的。

    8、使用Swing做界面,使用Java 6 SE的Swing,做了系統(tǒng)托盤Tray的支持等等。由于Swing的UI設(shè)計(jì)工具很不穩(wěn)定,最終完全手工編寫UI部分代碼,雖然辛苦,但是代碼簡(jiǎn)潔,不同UI Designer生成的那樣。

    9、我期望4月初發(fā)布一個(gè)版本,提供一個(gè)基本可用的版本。

    10、我是從1月初開始學(xué)習(xí)JXTA的,到現(xiàn)在還不滿3個(gè)月,其中還包括過年回家休息等等,玩游戲沉迷等等,但總的來說,我對(duì)這個(gè)學(xué)習(xí)速度很滿意。不過其中感覺最爽的是,在這個(gè)過程中,編碼時(shí),基本純鍵盤操作,不用鼠標(biāo),如行云流水一邊,十分流暢,工作效率高,人也舒服。




    溫少 2007-03-25 06:39 發(fā)表評(píng)論
    posted @ 2007-03-25 06:39 溫少的日志 閱讀(266) | 評(píng)論 (0)編輯 收藏
     
    1、使用多路復(fù)用或者異步I/O模型,這本是服務(wù)器段常用的技術(shù),但在P2P應(yīng)用,每臺(tái)機(jī)器既是服務(wù)器,又是客戶端,共享了一個(gè)十分受歡迎的文件,可能會(huì)有很多希望連接者,或者你下載一個(gè)受歡迎文件時(shí),可能搜索到數(shù)百上千的Peer,此時(shí)就很有必要采用多路復(fù)用或者異步I/O技術(shù),降低應(yīng)用程序所占用的資源。

    2、支持傳統(tǒng)的協(xié)議,包括HTTP和FTP,其實(shí)這兩種技術(shù)能夠和P2P網(wǎng)絡(luò)集成,其中一種辦法就是,在提供下載地址的同時(shí)提供一個(gè)種子文件下載,例如服務(wù)器中提供了ABC.rar文件,同時(shí)提供一個(gè)ABC.rar.md5文件允許下載,這樣P2P下載工具下載時(shí),通過md5在P2P網(wǎng)絡(luò)中搜索更多的資源,這樣客戶能夠獲得更好的速度,服務(wù)器端也可能降低下載的網(wǎng)絡(luò)流量。

    3、流行的P2P網(wǎng)絡(luò)協(xié)議支持,包括BT和emule,這兩種都是公開協(xié)議了,都有開源的實(shí)現(xiàn),可以參考并重寫,要支持并不困難。

    4、健壯性。如同emule一樣,將文件分塊(piece)的同時(shí),把每一塊摘要一個(gè)piece_ID,將所有的piece_ID再摘要成一個(gè)總的ID,成為AICH。其實(shí)這也是一種很簡(jiǎn)單的技術(shù),實(shí)現(xiàn)起來并不困難,做法可以多種多樣。

    5、對(duì)大型局域網(wǎng)有特別支持。現(xiàn)實(shí)中,存在很多大型的局域網(wǎng),局域網(wǎng)之間的擁有高速的帶寬。對(duì)局域網(wǎng)的特別支持辦法也有很多的,例如,類似BT那樣,在局域網(wǎng)里建立一個(gè)Tracker Server。若是基于JXTA,可以在局域網(wǎng)里部署聚合點(diǎn)(Rendezvous)

    6、支持P2P目錄共享,現(xiàn)在流行的P2P下載工具,都不支持以目錄為單位實(shí)現(xiàn)P2P共享和下載。其實(shí)支持P2P目錄共享也不困難,在提供共享時(shí),提供一個(gè)目錄結(jié)構(gòu)信息就可以了。目錄結(jié)構(gòu)信息dir_info可以這樣記錄:子文件或子目錄路徑 偏移量 長(zhǎng)度。當(dāng)然把目錄壓縮然后提供下載也是可以的,不過這樣會(huì)浪費(fèi)共享者的磁盤空間。目錄共享,要考慮共享之后文件進(jìn)行修改,添加新文件等事情,使用dir_info能夠更好解決這種問題。

    7、關(guān)于通告。一個(gè)P2P共享資源(包括文件和目錄),應(yīng)該包括三個(gè)ID:content_id、aich_id、dir_info_id。其中content_id是整個(gè)資源的摘要,aich_id是每塊id進(jìn)行摘要產(chǎn)生的id,dir_info_id是dir_info的摘要id。
    content_id可用資源搜索,建議采用MD5摘要產(chǎn)生,因?yàn)楝F(xiàn)在很多網(wǎng)上提供下載的文件,都提供一個(gè).md5后綴的校驗(yàn)文件。
    aich_id用于校驗(yàn)和智能恢復(fù)
    dir_info_id。如果計(jì)算content_id時(shí),dir_info獨(dú)立計(jì)算,則需要提供dir_info_id,用于校驗(yàn)dir_info。理論上dir_info可以作為content的一部分,但是我覺得dir_info獨(dú)立計(jì)算會(huì)帶來很多好處。

    8、關(guān)于傳輸。資源的傳輸,應(yīng)該包括三部分,hashset的傳輸、dir_info的傳輸、內(nèi)容數(shù)據(jù)的傳輸。內(nèi)容傳輸是分塊傳輸?shù)模矣X得采用BT的默認(rèn)值256K一塊挺好的。每一塊(piece)摘要計(jì)算一個(gè)piece_id,所有的piece_id放在一起,就是一個(gè)hashset,hashset這個(gè)名字不大好,不直觀,但既然emule協(xié)議是這樣會(huì)說,我也這樣說好了。dir_info是可選的,文件共享不帶dir_info。

    9、P2P下載技術(shù)的應(yīng)用范圍應(yīng)該擴(kuò)展,程序的安裝更新都應(yīng)該加入P2P的支持,將會(huì)大大提高程序的用戶體驗(yàn)。

    10、P2P的平臺(tái)應(yīng)該具備良好的擴(kuò)展性。當(dāng)我們構(gòu)建起一個(gè)龐大的P2P平臺(tái)時(shí),不單單只是在其上共享文件,有很多應(yīng)用可以部署在其上,包括現(xiàn)在很流行的P2P視頻,分布式計(jì)算等等。即時(shí)通訊也是可以構(gòu)建在P2P網(wǎng)絡(luò)上的。面對(duì)眾多的應(yīng)用需求,我們需要一個(gè)具備良好擴(kuò)展性的協(xié)議,不應(yīng)該像BT和emule那樣,除了下載,別無它用。可能基于JXTA是一種較好的選擇。

    11、安全。P2P網(wǎng)絡(luò)應(yīng)該支持安全特性,一些團(tuán)體,一些企業(yè),需要限定范圍內(nèi)共享資源。例如NASA的衛(wèi)星數(shù)據(jù)共享項(xiàng)目SAXTA,采用JXTA,就是因?yàn)镴XTA支持安全特性。我想很多的P2P應(yīng)用場(chǎng)景,都需要安全,例如,企業(yè)只希望內(nèi)部員工之間實(shí)現(xiàn)P2P資源共享等等。



    溫少 2007-03-25 05:47 發(fā)表評(píng)論
    posted @ 2007-03-25 05:47 溫少的日志 閱讀(222) | 評(píng)論 (0)編輯 收藏
     
    主站蜘蛛池模板: 国产女高清在线看免费观看| 国产成人亚洲综合一区| 久久国产美女免费观看精品| 国产免费观看a大片的网站| 亚洲一卡2卡3卡4卡国产网站| 免费视频成人手机在线观看网址| 国产福利电影一区二区三区,亚洲国模精品一区 | 国产妇乱子伦视频免费| 久久综合图区亚洲综合图区| 久久国产美女免费观看精品| 亚洲精品尤物yw在线影院| 疯狂做受xxxx高潮视频免费| 免费看AV毛片一区二区三区| 亚洲性线免费观看视频成熟| 99久久99这里只有免费费精品| 综合自拍亚洲综合图不卡区| 久久久久国色av免费看| 久久精品亚洲综合| 久久99免费视频| 亚洲av无码专区国产乱码在线观看 | 日韩精品视频免费网址| 中文字幕无码亚洲欧洲日韩| 国产免费不卡v片在线观看| 91嫩草亚洲精品| 18禁止观看免费私人影院| 亚洲国产精品人久久电影| 亚欧人成精品免费观看| 亚洲最大视频网站| 日韩精品免费一级视频| tom影院亚洲国产一区二区| 9久9久女女免费精品视频在线观看| 亚洲国产成人91精品| 青苹果乐园免费高清在线| 亚洲xxxx视频| 韩国免费三片在线视频| 亚洲av综合日韩| 亚洲精品成人区在线观看| 黄视频在线观看免费| 国产亚洲综合色就色| 午夜影院免费观看| 亚洲春黄在线观看|