新寫了一個Java并發程序設計教程, 用于公司內部培訓的,和2007年寫的那個相比,內容更翔實一些。
內容列表
1、使用線程的經驗:設置名稱、響應中斷、使用ThreadLocal
2、Executor :ExecutorService和Future ☆ ☆ ☆
3、阻塞隊列 : put和take、offer和poll、drainTo
4、線程間的協調手段:lock、condition、wait、notify、notifyAll ☆ ☆ ☆
5、Lock-free: atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList ☆ ☆ ☆
6、關于鎖使用的經驗介紹
7、并發流程控制手段:CountDownlatch、Barrier
8、定時器: ScheduledExecutorService、大規模定時器TimerWheel
9、并發三大定律:Amdahl、Gustafson、Sun-Ni
10、神人和圖書
11、業界發展情況: GPGPU、OpenCL
12、復習題
下載地址:
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
Google云計算AppEngine
Java版剛剛推出來的時候,我就申請了該服務。該服務的申請需要提供手機號碼驗證,GOOGLE很牛B,能夠發送全球的手機短信。申請的帳號放了很久,
前段時間學習OpenID,需要作一個范例,于是就在Google
AppEngine上作,作的過程發現其不能使用線程,導致HttpClient組件無法工作,于是我修改了OpenID4Java的實現,全部使用
URLConnection來實現。最終程序部署成功了,網址 http://cogito-study.appspot.com,歡迎大家測試使用。
我來說一下我對Google AppEngine Java版本的使用感受吧。
1、
Google AppEngine
Java版本,具備基本功能,但是由于缺乏一些重要的功能,例如線程,沒有線程,很多庫無法使用,例如我上面提到的HttpClient不能使用。
Google提供一個類的白名單http://code.google.com/intl/zh-CN/appengine/docs/java
/jrewhitelist.html,大多數需要使用的類都有,javax.xml.crypto不再其中,使得我要部署一個SAML2的實現時玩不
轉。
2、Google
AppEngine提供了一個DataStore,使用JDO訪問數據,其查詢語言支持GQL。基本功能是具備的,但是也是存在很大的局限性,最多返回
1000行數據,COUNT(*)也是最多返回1000行。這個限制使得很多應用要跑在其上,會很麻煩。
3、部署很簡單,在Eclipse中使用Google提供的插件,輸入帳號密碼就可以部署了,太簡單了。但我使用的過程中,經常出現某些時段無法部署的情況,通常遇到這種情況,多嘗試幾次或者過段時間再嘗試就好了。
4、管理界面簡潔方便,功能基本完備。包括性能監控、數據管理、日志、計費等都有。
總結
Google的AppEngine Java版本已經具備了基本功能,可以部署簡單應用了,但是由于其功能不夠完備,目前大多數應用要部署在其上,都會要做相當大的修改或者無法實現。
我在Google AppEngine上部署了一個Java應用(OpenID測試)
http://cogito-study.appspot.com
Google Apps不支持線程,所用到的庫openid4java需要創建線程(因為HttpClient),我修改了openid4java的實現,使得其支持Google App Engine。
部署在Google App Engine上的應用可以應用任何OpenID Provider登陸,包括Google、Yahoo、MSN等。
你可以通過這個測試網站了解OpenID
最近花了較多時間學習單點登陸以及相關的安全技術,做一個簡單的總結,發表我的一些看法。拋磚引玉,希望各位朋友參與討論。
單點登陸,鳥語原文為Single Sign-On,縮寫為SSO。別以為單點登陸是很時髦高深的技術,相反單點登陸是很古老的技術,例如1980年kerberos v4發布,一直發展至今,被Windows、Mac OS X、Linux等流行的操作系統所采用,是為應用最廣泛的單點登陸技術。
kerberos適用于局域網,十分成熟。互聯網發展之后,多個網站需要統一認證,業界需要適合互聯網的單點登陸技術,也就是WEB SSO。2002年,微軟提出了passport服務,由微軟統一提供帳號和認證服務,理所當然,大家都不愿意受制于微軟,但是很認同微軟提出WEB SSO理念,于是產生了Liberty Alliance,另外指定一套標準,這套標準發展起來就是SAML,目前SAML的版本是SAML V2,屬于OASIS的標準。
--------------
SAML
SAML,鳥語全名為Security Assertion Markup Language,彌漫著學院派的腐尸味道,縮寫十分怪異,令人望而生畏。計算機行業,向來崇尚時髦,SAML這一名稱使得其較少受到大眾程序員的關注。
SAML的標準制定者,來自SUN、BEA、IBM、RSA、AOL、Boeing等大公司,制定技術規范相當專業有水準,系統分層合理,抽象了幾個概念把整個系統描述得很清楚,使用流行技術XML Schema來描述協議,使用到了XML-Sign和XML Encrypt等較為前緣XML安全技術。
SAML的基本部分包括Protocol、Bingding、Profile、Metadata、AuthenticationContext。其中Protocol是交互消息的格式,例如AuthnRuequest/Response(認證請求/響應)的消息對。Bingding是指協議所采用的傳輸方式,例如使用HTTP Redirect或HTTP POST或SOAP的方式傳輸Protocol中所定義的消息。Profile是系統角色間交互消息的各種場景,例如Web Single Sign-ON是一種Profile、Single Sign-Out也是一種Profile、身份聯邦也是一種Profile。各個參與方所提供的服務的描述信息為metadata。系統的認證方法通常是千差萬別的,AuthenticationContext是SAML中定義的認證擴展點,可以是最普通的User Password認證,也可以是kerberos認證,也可以是電信常用的RADIUS,或者是動態密碼卡。
SAML在Java企業應用中,得到廣泛支持,IBM、BEA、ORACLE、SUN的Java應用服務器都提供了SAML的支持,曾經有人說,SAML就是如同JDBC一樣,將會是使系統集成的準入證。SAML有很多開源實現,包括SUN公司的Open SSO,不幸的是,這些開源實現都不夠好,或者相當糟糕,如果我們需要支持SAML協議,可能需要在開源的版本上裁剪或者另行開發。
SAML考慮了Web SSO,也考慮了傳統的SSO集成,包括Kerberos和LDAP的集成,其中Attributed擴展機制以及相關規范,使得SAML擁有良好的擴展性,很好集成傳統協議和支持新協議。
SAML是一個定義良好的規范,概念清晰,分層合理,擴展性良好,一切都很棒,但是有一點不好,就是曲高和寡!
-------------
OpenID
有一些互聯網公司,擁有眾多很多帳號,很牛B,例如GOOGLE、YAHOO、Facebook,希望別人的系統使用它們的帳號登陸。他們希望一種足夠簡單的WEB SSO規范,于是選擇一種草根網絡協議OpenID。OpenID,名字取得好,顧名思義,一看就知道它是干嘛的。國內也有它的Fans,例如豆瓣網。openID的確足夠簡單,但是協議本身是不完善,可能需要一些補充協議才能夠滿足業務需求。例如GOOGLE采用OpenID + OAuth。目前支持OpenID有Yahoo、Google、Windows Live,還有號稱要支持OpenID的Facebook。目前Yahoo和Google宣稱對OpenID的支持,但是其實是有限制的,Yahoo的OpenID只有少數合作伙伴才能獲得其屬性,Google也只有在其Google Apps中才能獲得賬號的Attribute。用戶賬號畢竟是一個互聯網公司的最寶貴資源,希望他們完全分享賬號是不可能的。
Open ID和SAML兩種規范,都將會減少系統間交互的成本,我們提供Open API時,應該支持其中一種或者或兩種規范。
--------------
OAuth
oAuth涉及到3大塊的交互和通信。1. 用戶,2. 擁有用戶資料/資源的服務器A,3. 求資源的服務器B,。
oAuth的典型應用場景(senario)
以前,用戶在 擁有資源 的的網站A有一大堆東西;現在用戶發現了一個新的網站B,比較好玩,但是這個新的網站B想調用 擁有資源的網站A的數據。
用戶在 求資源的網站B 上,點擊一個URL,跳轉到 擁有 資源的網站A。
擁有資源的網站A提示:你需要把資源分享給B網站嗎?Yes/No。
用戶點擊 Yes,擁有資源的網站A 給 求資源的網站B 臨時/永久 開一個通道,然后 求資源的網站 就可以來 擁有資源的網站 抓取所需的信息了。
(參考資料:http://initiative.yo2.cn/archives/633801)
(摘抄)
--------------
內部系統間集成使用LDAP、Kerberos,外部系統集成使用SAML或者OpenID + OAuth,這是一種建議的模式。
------------
PAM
人們尋找一種方案:一方面,將鑒別功能從應用中獨立出來,單獨進行模塊化設計,實現和維護;另一方面,為這些鑒別模塊建立標準 API,以便各應用程序能方便的使用它們提供的各種功能;同時,鑒別機制對其上層用戶(包括應用程序和最終用戶)是透明的。直到 1995 年,SUN 的研究人員提出了一種滿足以上需求的方案--插件式鑒別模塊(PAM)機制并首次在其操作系統 Solaris 2.3 上部分實現。插件式鑒別模塊(PAM)機制采用模塊化設計和插件功能,使得我們可以輕易地在應用程序中插入新的鑒別模塊或替換原先的組件,而不必對應用程序做任何修改,從而使軟件的定制、維持和升級更加輕松--因為鑒別機制與應用程序之間相對獨立。應用程序可以通過 PAM API 方便的使用 PAM 提供的各種鑒別功能,而不必了解太多的底層細節。此外,PAM的易用性也較強,主要表現在它對上層屏蔽了鑒別的具體細節,所以用戶不必被迫學習各種各樣的鑒別方式,也不必記住多個口令;又由于它實現了多鑒別機制的集成問題,所以單個程序可以輕易集成多種鑒別機制如 Kerberos 鑒別機制和 Diffie - Hellman 鑒別機制等,但用戶仍可以用同一個口令登錄而感覺不到采取了各種不同鑒別方法。PAM 后來被標準化為 X/Open UNIX® 標準化流程(在 X/Open 單點登錄服務(XSSO)架構中)的一部分。(摘抄)
如果我們設計一個認證系統,PAM是應該參考借鑒的。
-------------
JAAS
Java Authentication Authorization Service(JAAS,Java驗證和授權API)提供了靈活和可伸縮的機制來保證客戶端或服務器端的Java程序。Java早期的安全框架強調的是通過驗證代碼的來源和作者,保護用戶避免受到下載下來的代碼的攻擊。JAAS強調的是通過驗證誰在運行代碼以及他/她的權限來保護系統面受用戶的攻擊。它讓你能夠將一些標準的安全機制,例如Solaris NIS(網絡信息服務)、Windows NT、LDAP(輕量目錄存取協議),Kerberos等通過一種通用的,可配置的方式集成到系統中。在客戶端使用JAAS很簡單。在服務器端使用JAAS時情況要復雜一些。(摘抄)
-------------
Spring Security,Spring框架大名鼎鼎,Spring Security屬于SpringFramework旗下的一個子項目,源自acegi 1.x發展起來。很多人項目應用了spring security,但我個人看來,spring security絕對不算是一個設計良好的安全框架。其設計感覺就是一個小項目的安全認證實踐罷了。
-------------
CAS
應用最廣的開源單點登陸實現了,其實現模仿Kerberos的一些概念,例如KDC、TGS等等,都是來自于Kerberos。CAS對SAML和OpenID協議支持得不夠好。個人感覺類似Kerberos的機制在互聯網中可能過于復雜了。我感覺單純的ticket機制,過于局限于基于加密解密的安全了,感覺上SAML的Assertion概念更好,Assertion可以包括認證、授權以及屬性信息。
-------------
--------------------------
09博客園紀念T恤
新聞:
Wordpress發布實時RSS技術 推動實時網絡發展
網站導航:
博客園首頁 個人主頁 新聞 社區 博問 閃存 找找看
現在很多開源項目在使用LOG的時候做了不好的示范--在基類中實例化的方式使用LOG,而不是靜態變量。
例如:
class Base {
private final Log LOG = LogFactory.getLog(this.getClass());
}
class Derived {
public void foo() {
if (LOG.isDebugEnabled()) LOG.debug("foo");
}
}
這種用法,當類被繼承的時候,LOG就完全亂了。spring、struts都有這樣的問題。
正確的使用方式應該是直接靜態化聲明LOG。
例如:
class DerivedA {
private final static Log LOG = LogFactory.getLog(DerivedA.class);
}
--------------------------
盛大招聘.Net開發工程師
經典好書:.NET框架程序設計(修訂版)
新聞:
2008年最精彩科技圖片:電流運動模擬圖居首
導航:
博客園首頁 知識庫 新聞 招聘 社區 小組 博問 網摘 找找看
文章來源:
http://www.cnblogs.com/jobs/archive/2009/01/05/1368894.html
Eclipse包含很多插件,插件之間有復雜的依賴關系,如果使用單獨下載安裝的方式,容易遺失部分需要依賴的插件。
在Ecliipse的Software Update功能中安裝插件,能夠解決插件依賴的問題,但是在Eclipse 3.4之前的版本,Software Update不能夠多線程同時下載,遇到網速較慢的更新站點時,需要漫長的等待,有時候安裝一個插件,需要數個小時,甚至更久。
在Eclipse 3.4之后,Software Update有了很大的改變,可以多線程下載了,但是不能手工選擇鏡像,它會笨笨的選擇一些很慢的站點,效果變得更差了,下載速度時快時慢,但是經常都比以前手工選擇鏡像要慢。經常選擇一些只有數百B速度的下載站點,令人抓狂!
所以說,Eclipse 3.4的Software Update功能依然令失望。
期待數年,終于盼來了新版的Software Update功能,但是新版的更差了,哎。。。
摘要: 我們在開發中,經常需要遍歷一個目錄下的所有文件,常用的辦法就是使用一個函數遞歸遍歷是常用的辦法。但是遞歸函數的缺點就是擴展不方便,當然你對這個函數加入一個參數FileHandler,這樣擴展性稍好一些,但是仍然不夠好,比如說,不能根據遍歷的需要中途停止遍歷,加入Filter等等。我實現了一個FileIterator,使得遍歷一個目錄下的文件如何遍歷一個集合中的元素一般操作。
閱讀全文
http://openjdk.java.net/上的Announcements:
2008/04/28
New Project approved: More New I/O APIs for the Java
Platform
包括內容:
- 4313887 New
I/O: Improved filesystem interface
- 4640544 New
I/O: Complete socket-channel functionality
- 4607272 New
I/O: Support asynchronous I/O
讓人期待太久太久了,終于來了,Java在大規模并發、高性能方面又進一步,JSR 203應該會在JDK 7中實現,屆時隨著JDK 7的發布,將會有更多的基礎軟件使用Java實現,而且有極好的性能。
在磁盤I/O和網絡大規模并發I/O方面都會得到更好的性能。
可以預見受益的程序:
1、WEB服務器 Tomcat、Jetty等,在Windows下,Java將可以使用IOCP,而不是現在nio所用的select,網絡并發性能將會得到大幅度提升。在Linux下則應該改變不多,畢竟linux現在并發最好性能的網絡I/O EPOLL,JDK 6.0 nio的缺省實現就是epoll。
2、數據庫應用程序。如Derby、Berkeley DB Java Edition等使用Java實現的數據庫,性能將會得到更好的提升,有望能夠誕生和Oracle、SQL Server一樣強大的100% Pure Java的數據庫系統。
3、其他網絡應用程序。例如DNS、LDAP等,隨著MINA之類的框架更強大和JDK的原生支持,將會越來越多的服務器程序使用Java實現。
在新項目中,除了一些框架所依賴的配置文件使用XML外,基本沒有使用XML。JSON基本替代了原來XML在程序內的位置。在以前,我們不愿意使用一種私有的格式,于是選擇了XML。選擇XML的理由,可能是大家都用它,所以我們也用它。
XML 是一種很好的技術,但是目前的情況來看,XML被濫用了,SOAP是XML被濫用的一種典型,程序內部的表示使用XML也是濫用的一種典型。看到的一種情況,一個對象toString使用XML格式輸出,導致日志文件十分羅嗦,調試時,在watch窗口中看到一大堆<tag>。
在新項目中,認真考慮這種情況,找到了另外一種選擇,那就是JSON。選擇JSON的理由很充分:
1、JSON的解釋性能要比XML要好,要簡潔緊湊。
2、可讀性要比XML好。JSON本身就是JavaScript的語法,和程序員的思維,而非文檔編寫的思維。
3、JavaScript原生支持,客戶端瀏覽器不需要為此使用額外的解釋器,在web環境中使用特別合適。
在java中使用json,目前需要注意一些情況:
1、目前開源的JSON-LIB代碼質量不好,最好是在此基礎之上修改一個版本,或者自己重新開發一個版本。
2、使用new Date的方式替代JSON-LIB中的{year:2007, month:12, ....}之類的方式
3、JSON-LIB中,object的propertyName在輸出的時候,都帶上"",例如{"name": "溫少"}, 其中name是的雙引號是不必要的,在輸出時應該判斷,不需要的就是就不加上"",減少網絡流量。
4、JSON的解釋器中,應該支持簡單的表達式,例如new Date()、new Date(2939234723)之類的,這使得JSON的表達能力會更強一些。
5、JSON應該分兩種,一種只支持簡單格式,類似開源的JSON-LIB,一種是通過JavaScript解釋器來實現的。后者在程序中傳輸數據時,能夠得到更強大的表達能力,但是也會導致安全問題,需要慎重使用。
1、
XP中的結對編程。XP編程中,有一些思想總結的很好,例如測試驅動,但又有極度的荒唐的就是結對編程。結對編程是我看到過的最荒唐最可笑的軟件工程方
法,兩倍的投入,一半的產出,可謂事倍功半。以前看結對編程只是覺得荒唐可笑,后來看了李安的電影《斷背山》,覺得以“斷背”來形容結對編程最適合了,結
對編程簡直就是專門為“男同志”們度身定做的軟件工程方法,你想一對“男同志”,每天手牽手背靠背進行“結對編程”,是多么“浪漫有趣”的事情。不過這只
對“男同志”們的浪漫有趣,對工作本身一點也不有趣!
--------------
2、JDO投票鬧劇(2004-2005)。
一個通過黑客式靜態AOP方式旁門左道實現的持久化技術JDO,竟然會被一些人追捧,這本身就是一個很荒唐的事情了。在JCP的投票中,JDO被否決了,
這一點也不奇怪,奇怪的是投票結果出來之后的鬧劇。一些人以“政治陰謀論”來說事,說JDO不被通過,是因為政治原因,而非技術原因,這個荒唐的理由竟然
被社區的很多人相信了,一片聲討,JCP迫于壓力,重新投票,通過了JDO相關的JSR。但是JDO并沒有因此有一點點起色,一直沉淪至今。JDO通過靜
態AOP(enhance)的方式使得代碼無法調試,就單這一點,就足以使JDO永遠無法流行。
這件事情很明確表明兩點:1)、不要相信一些技術作家的判斷力;2)、普通的大眾沒有判斷能力,會人云亦云。
當年荒唐的文章選錄:
《程序員》2005年第2期 http://blog.csdn.net/gigix/archive/2005/01/21/262163.aspx
---------------
竟
然64個annotation,沒有分類,放在同一個package下,同一個package(javax.persistance)還有其他java文
件,共有88個java文件。不看內容本身,單從表面,都覺得這是混亂不堪的事情。這是那個豬頭的杰作?glassfish上下載的源碼中,這些java
文件似乎都沒有author,估計也不好意思把名字放出來見人吧!
------
覺得對象關系存儲方面一直沒有突破,也沒有好的產品出來,其中一個原因,就是從沒有過優秀的工程師投身過這個領域。關系數據庫為什么能夠一直堅守領地,成為絕大多數商業應用的基石,其中一個原因就是有過大量的精英投身于此,包括兩個圖靈獎獲得者。
關
系數據庫,為了描述關系,創造一門SQL語言,將關系一些操作,例如投影(select)、選擇(where)、分組(group
by)等等,抽象得形象易懂,功能強大。對于數據的操作,SQL語言是最強大,也是最方便的,也是最易于使用的。一些非程序員的IT從業人員,非計算機專
業的人員都能夠熟練掌握SQL。
OO和Relational都是偉大的技術,從計算機最高榮譽獎可以看出這兩個技術的偉大。OO的圖靈獎獲得者是三個,Relational的圖靈獎獲得者是兩個。
面向對象技術自1967年simula引進以來,所想披靡,93年-98年從C++開始流行,然后到Java,成為主流編程技術。Relational沒有OO那么輝煌,但是在數據存儲方面的地位固如磐石,長期占據絕對的地位。
曾
經OO技術涉足于數據存儲領域,但終究沒有成功。面向對象數據庫的變現總是差強人意,面向對象的方式操作數據,總是不如使用關系那么方便,那么靈活,那么
易于使用,那么好的性能。于是人們在數據存儲和處理方面,不在青睞面向對象技術,而是仍然使用關系方式,使用SQL語言,使用關系運算操作數據。面向對象
數據庫成了曇花一現的東西,并且可能永遠都不會再流行了。
OO成了主流編程技術,Relational占據了絕對的數據存儲地位,這兩大技術需要交互,需要橋接,這需要OR-Mapping。Relational雖然好,但我們也要與時俱進,所以也需要OR-Mapping。
但
是,做OR-Mapping時,不積極吸取relational方式對數據處理的靈活性、方便性、簡單性,而只強調Relational和對象之間的的
Mapping,試圖以面向對象的方式操作數據,這是錯誤的方向。以前的EJB、現在Hibernate、JPA都犯了同樣的錯誤,試圖以更面向對象的方
式操作數據,從而導致復雜混亂的模型,這也是JPA的現狀吧。例如user.getGroup(),目前的ORM試圖以純OO的方式操作數據,所引起的
LazyLoad、n+1等問題,使得事情變得復雜而且混亂不堪。
一些開發人員,去學習Hibernate,不學習SQL,有人提倡,只需要了解面向對象編程技術,不需要了解關系技術,亦屬于本末倒置。需求人員都會用的SQL語言,對數據操作最方便最簡單最強大的SQL語言,竟然成了令人生畏的紙老虎,可笑啊。
-------------
以下是過去的一些業界浮躁不理智:
1、面向對象數據庫。曾被熱衷而吹捧,面向對象數據庫的變現總是差強人意,面向對象的方式操作數據,總是不如使用關系那么方便,那么靈活,那么易于使用,那么好的性能。于是人們在數據存儲和處
理方面,不在青睞面向對象技術,而是仍然使用關系方式,使用SQL語言,使用關系運算操作數據。面向對象數據庫成了曇花一現的東西,并且可能永遠都不會再
流行了。
2、
JDO投票鬧劇。2004-2005年,JDO的JSR在JCP投票被否決的,無聊者在Java社區以及媒體發起鬧事,陰謀論其為政治謀殺,幾大公司是的
迫于形象,重新投票使得JDO被通過,但JDO這種靜態AOP叫雕蟲小計式技術,不單開發過程不方便,而且會使得"enhance"之后的代碼不可調試。
這完全是對開發者不友好的技術,沒有前途的技術,竟然會有人為它在JCP投票不通過鳴不平。這件事情使得我更堅信一點,不要相信那些技術編輯的判斷力。
3、
AOP。也是最近這幾年流行的一個名詞了。起了一個和OOP相似的名字,但是和偉大的OOP相比,它完全不算是什么。AOP只是一種很小很小的技巧而已,
靜態的AOP是黑客式的插入代碼,會導致代碼不可調試,動態的AOP能力有限,AOP最常被引用例子“日志AOP”是不合適,有用的日志通常是精心設計
的,AOP方式的日志在生產環境中基本上是不可用。OO這么多年,這么為偉大,人們總是希望自己能做點什么和偉大的OO相比,于是命名為AOP,這是一個
可笑的名字,前些年還有人談論面向對象的未來是面向事實,也是同樣的可笑。AOP有價值,但它是一種小技巧,和名字不般配。
--------------
目前在流行,但是可能是不理智的技術:
1、hibernate之類的ORM,試圖以面向對象方式操作數據,和面向對象數據庫一樣,重蹈覆轍。
2、Ruby,一個小腳本語言,只是因為動態類型、mixin之類的功能,還沒有被證明有生產力,有效益可用的腳本語言,就被媒體吹到天上去。Ruby有價值,但是最終結果會離大家的期待相差甚遠。
中國最大的在線記賬及商務管理平臺—金蝶“友商網”(www.youshang.com)正式上線!請立刻體驗!
摘要: 本文描述一種ID生成算法
閱讀全文
摘要: 本文介紹流行的非阻塞算法關鍵思想Compare And Set在數據庫開發中的應用
閱讀全文
由于在實際工作中使用到了mina,所以一直關注其mail-list。
最近mina的mail-list討論的一個問題,就是提供的manual close connector,這個問題可害慘我了。
原來的Connector,無論是SocketConnector或者VmPipeConnector,都是沒有提供close方法的,而且不會自動釋放。
原來做得一個網絡程序客戶端,每次重新創建的時候,都會new SocketConnector,可是,SocketConnector不會被GC回收的,所使用的線程和內存都不會自動釋放,這個程序在服務器斷開時會重連,于是,當服務器重啟或者網絡中斷時,內存泄漏就產生了,程序慢慢的占用更多的內存,直至崩潰!
解決此問題的辦法就是,要么使用Singleton,要么使用即將發布的1.1.3!
使用maven2一段時間了,我基本把我自己能夠遷移的project都轉換為maven2 project,以下是我的一點感想。
(原作者溫少,轉載請注明)
亂世盼英雄
現在的軟件開發,比過去的軟件開發要復雜得多。包括在參與開發的人數、代碼規模、復雜的需求、依賴包的復雜性、使用到更多的技術、多個項目之間的復雜依賴關系。
現在的開發人員,要掌握的技術要比過去的開發人員要多,不是現在的開發人員比以前的開發人員本身更優秀,而是擁有更多的資料、更多的學習機會、更多更大規模的時間,同時軟件行業也在發展。說一句題外話,老程序員,如果不與時俱進,靠老本,是無法和新一代程序員競爭的,當然,老程序員,擁有更多的經驗,掌握新技術的速度更快,這又是另外一回事。
開發人員掌握的技術更復雜了,項目用得的技術自然也是更復雜,例如一個web項目,可能使用到很多技術,面向對象、泛型、or-mapping、依賴注入(spring-framework)、全文檢索(lucene)、數據庫、集群、工作流、web service等等。
由于使用了多種技術,這些技術可能是JDK提供的,也可能是第三方開源組織提供的,或者不同的商業公司提供的。
于是出現了一個新的難題,就是包依賴復雜性。以前,你很難想象你的代碼依賴數十個不同開源組織、商業公司提供的庫。例如,我們經常使用的log4j、junit、easymock、ibatis、springframework,每個組件都有悠久的歷史,存在不同的版本,他們之間版本還有依賴關系。
項目依賴的復雜性,經常的,一個較大部門有10-30個項目是常事,項目之間有不同版本的依賴關系,部門與部門之間的項目也存在復雜的版本依賴關系。
Eclipse本身提供Project的依賴,但是簡單的依賴顯然解決不了問題。例如Project B依賴Project A,Project A依賴第三方的jar包abc-1.0.jar,那么需要在兩個項目的lib下都存放abc-1.0.jar,這產生冗余,當Project數量多起來,這個冗余就產生了管理問題,如果需要將abc-1.0.jar升級為abc-1.1.jar,則需要在兩個Project中同時修改,如果Project數量達到10個以上,而且是不同項目組維護的項目,這個就是非常麻煩的事情。而且Project A修改依賴,為啥需要Project B也作相應的修改呢?
需要解決此問題,就需要在Project A的包中描述其依賴庫的信息,例如在META-INFO記錄所以來的abc-1.0.jar等。Eclipse的plug-in擁有類似的方案,但是這樣一來,就使得開發Project B的項目組,需要把Project A的代碼從源代碼庫中check out出來。在依賴鏈末端的項目組是很慘的。
由于Project數量眾多,關系復雜,dailybuild的ant腳本編寫成了很麻煩的事情,使用Project依賴的方式,更加使得編寫dailybuild ant script是非常痛苦的事情。
當然也可以不使用project依賴的方式,而使用artifact lib的依賴方式,但是artifact lib的依賴方式,就是同時修改多個project,互相調試時帶來了痛苦。
在以前,我們面臨這些問題時,唯一的感覺就是,這事情TMD的太麻煩,幾乎是失控了。
maven的出現,解決這種問題看到了希望。maven出現的原因就是,現在的開發管理復雜度達到了一定程序,需要專門的開發管理工具,這樣的工具需要涵蓋開發的各個階段,包括工程建立、配置依賴管理、編譯、測試、產生分析報告、部署、產生制品等階段。目前,各個階段的工具都存在,但是不是集成的,對使用帶來了很大麻煩。maven集成了這些工具,提高了統一的環境,使得使用更簡單。
現在maven非常流行了,apache上所有java project都已經build by maven,其他跟進的開源項目非常多,例如mule、hibernat等等,商業公司也很多在采用,sun公司提供有maven2 repository。
現在,2007年,如果你還沒采用maven project,你可能需要思考一下,是否你使用了不恰當的方式管理的代碼,或者你落伍了?
maven的一些常用任務
compile 編譯代碼
test 運行單元測試
package 打包代碼
site 產生報告,例如java doc、junit的通過率報告和覆蓋率報告、findbugs的分析報告等等。
assembly 使用需求產生assembly,例如把生成一個程序目錄,包括bin、config、lib、logs,把依賴包放在lib中。
deploy 部署制品到repository中。
這些都是常用的任務,在以前編寫腳本很麻煩,現在在maven中,一切都是很簡單,需要仔細設置時功能又強大到令人驚嘆,例如site的fml,assembly。
maven資源庫
maven官方提供了一個常用lib的資源庫,包括apache的所有java項目,開源常用的基本都能夠找到,例如mule、c3p0、easymock、hibernate、springframework、json等等,版本齊全,任你挑選。
可以部署本地資源庫代理提高下載速度。使用maven proxy。
maven體系結構
maven使用plug-in的體系,使用很好的自動更新策略,本身用到的jar都是lazy download的,可以指定download的repository。這樣,初始下載的maven是一個很小的程序,使用的時候從本地的資源庫或者本地代理資源庫高速下載lib。maven的插件體系,充分利用了internet的資源豐富和局域網的高速帶寬,使用本地repository時,可以享受到每秒鐘數M的下載速度,感覺就是,人生真是美妙!
elcipse的plug-in體系,就不是那么好用了,我們使用eclipse的find and install功能下載或者更新插件時,慢如蝸牛,依賴缺失時的煩惱,更新一個plug-in,可能耗費你數個小時,第三方的plug-in的下載服務器可能更慢,例如subversive的plugin-in,有一次我花了兩天還沒下載好,只好使用下載工具下載好,copy到plug-in目錄下。此時,我們總是感嘆,人生總是有很多煩惱事啊!
相比之下,高下立判!在此我不是說eclipse的plug-in體系結構設計不好,eclipse的插件體系非常優秀,但是還有很大改進空間!
在beep4j上作了一些修改,并且在此之上實現了一個基于BEEP協議的服務器框架。
BEEP協議提供了Session、Channel、Greeting、Profile、Frame等概念,這些基礎概念之上,很容易進行更高級的應用層協議設計。
BEEP協議的特征和能力
長連接
對等通訊
請求\應答式交互
在一個Session中創建多個獨立的傳輸通道(Channel)
在一個通道中進行多個異步請求(滑動窗口)
可以使用不同的消息編碼方式,包括二進制、文本、XML等,類似SMTP的MIME,使得可以在高效的二進制、易懂的文本之間作出選擇。
這是一個在傳輸層和應用層之間的協議,應用場景很廣泛,RFC標準化,官方網站為http://www.beepcore.org/。很多公司都有相應的支持,包括IBM。在不同語言下都是相應的實現,包括C、Java、Python、Ruby、JavaScript Beep client等等。
關于ContentType和Codec
在Java程序之間通訊,前期可能不希望作更多的協議編碼、解碼工作,使用spring bean xml格式傳輸是一種方式。
在一些對效率不是特別高,又不喜歡使用機器友好的XML的場景,可以使用JSON的編碼方式。
在一些對效率要求很高的場景,ASN.1或者自定義的二進制編碼格式。
甚至使用土土的序列化編碼方式
匆忙寫成,以后會慢慢補充
請用力一擊中等規模的并發程序設計
http://www.cnblogs.com/Files/jobs/2007-5-9-concurrent-ppt.rar2007-5-10修改版(帶參考文檔)
http://www.cnblogs.com/Files/jobs/2007-5-10-concurrent-ppt.rar
2007年4月刊《程序員》,專題為“多核時下的軟件開發”。《程序員》并非陽春白雪,它面向大眾程序員。面向大眾的《程序員》介紹多核、并發,也意味著并發程序設計的開始進入中國大眾程序員的視野。
并發程序設計,在很多的書籍或者文章中,都會提到他的一個特點,復雜。這個特性,也導致了在以往并發程序設計只為高級程序員所專用。
復雜度并非事物的固有屬性,并發程序設計的復雜,是我們主觀認為。我們認為并發程序設計復雜,是因為我們還沒有掌握一些使其簡單化、清晰化的方法。當我們掌握相關方法,研究徹底,并發就會變得簡單。這個過程已經開始了。
以
往,我們需要直接使用一些低級并發概念來構造系統,不斷發明輪子,容易出錯,難以調試,這種的并發程序設計當然復雜,因此也只能為高級程序員所專用。如此
環境,就如同Dijkstra給我們帶來結構化程序設計之前的世界一般。很幸運的是,一些軟件業的先驅們,已經抽象出一些概念,能夠使得并發程序設計簡單
化,清晰化。例如Future、Lock-free思想等。
在主流編程語言中,Java走在最前頭,理念領先,提供了實用的庫。在
Java SE
5.0中就提供了util.concurent包,包括了Future、Executor、BlockingQueue等,一系列lock-free的數
據結構,例如ConcurrentMap。包括并發流程控制工具類:CountDownLatch、CycliBarrier。還有精巧好用的
DelayQueue(參考我之前寫過的文章http:
//www.cnblogs.com/jobs/archive/2007/04/27/730255.html)。使用這些概念以及提供的模式,能夠使
得編寫并發程序簡單化。
C++中,Herb Sutter在Visual C++中加入了很多支持并發的語法特性,包括atomic、future等。boost的線程庫開始引入了第一個高級概念barrier。
Windows
平臺本身提供了功能強大的并發API,包括WaitForSingle系列,WaitForMulti系列,Auto和Manual模式的Event等
等。.NET平臺基本沒有任何自有的并發庫和工具類,完全是Windows
API的簡單封裝。可以這么說,.NET的類庫沒有為并發作任何事情,完全吃Windows API的老本。
如同Herb Sutter認為,我們很幸運處于并經歷這個軟件大變革(并發)。并發進入主流這個過程將會延續數年,Herb Sutter認為是2007-2012。
參考我以前寫的一篇文章(Herb Sutter的一些觀點 http://www.cnblogs.com/jobs/archive/2006/11/12/558078.html)
類
似的場景也有,早期面向對象技術,也只為少數高級程序員所掌握,現在剛入門的程序員都能說上一大通。數據結構算法也是,早期只為少數優秀程序員所掌握,但
現在主流的開發環境中就包括了主要的數據結構和算法,會用的人一把一把,會用List、Hashtable、快速排序一點也不酷。并發程序設計也一樣,將
不再是陽春白雪!
面向對象技術在最初在Simula語言中引進,顧名思義,最初樸素的面向對象思想就是模擬,在程序中模擬真實世界。這種
“模擬”,使得程序的組織清晰化,簡單化。但真實世界是充滿著并發。真實世界的并發要比虛擬環境中的并發要復雜的多,但是人們輕松應付,由此,我們有足夠
的理由相信,并發程序設計將不會是一種復雜難掌握的技術。
我們談一下實際的場景吧。我們在開發中,有如下場景
a) 關閉空閑連接。服務器中,有很多客戶端的連接,空閑一段時間之后需要關閉之。
b) 緩存。緩存中的對象,超過了空閑時間,需要從緩存中移出。
c) 任務超時處理。在網絡協議滑動窗口請求應答式交互時,處理超時未響應的請求。
一種笨笨的辦法就是,使用一個后臺線程,遍歷所有對象,挨個檢查。這種笨笨的辦法簡單好用,但是對象數量過多時,可能存在性能問題,檢查間隔時間不好設置,間隔時間過大,影響精確度,多小則存在效率問題。而且做不到按超時的時間順序處理。
這場景,使用DelayQueue最適合了。
DelayQueue
是java.util.concurrent中提供的一個很有意思的類。很巧妙,非常棒!但是java doc和Java SE
5.0的source中都沒有提供Sample。我最初在閱讀ScheduledThreadPoolExecutor源碼時,發現DelayQueue
的妙用。隨后在實際工作中,應用在session超時管理,網絡應答通訊協議的請求超時處理。
本文將會對DelayQueue做一個介紹,然后列舉應用場景。并且提供一個Delayed接口的實現和Sample代碼。
DelayQueue是一個BlockingQueue,其特化的參數是Delayed。(不了解BlockingQueue的同學,先去了解BlockingQueue再看本文)
Delayed擴展了Comparable接口,比較的基準為延時的時間值,Delayed接口的實現類getDelay的返回值應為固定值(final)。DelayQueue內部是使用
PriorityQueue實現的。
DelayQueue = BlockingQueue + PriorityQueue + Delayed
DelayQueue的關鍵元素BlockingQueue、PriorityQueue、Delayed。可以這么說,DelayQueue是一個使用優先隊列(PriorityQueue)實現的BlockingQueue,
優先隊列的比較基準值是時間。他們的基本定義如下
public interface Comparable<T> {
public int compareTo(T o);
}
public interface Delayed extends Comparable<Delayed> {
long getDelay(TimeUnit unit);
}
public class DelayQueue<E extends Delayed> implements BlockingQueue<E> {
private final PriorityQueue<E> q = new PriorityQueue<E>();
}
DelayQueue內部的實現使用了一個優先隊列。當調用DelayQueue的offer方法時,把Delayed對象加入到優先隊列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方法,把優先隊列q的first拿出來(peek),如果沒有達到延時閥值,則進行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,是一個緩存的簡單實現。共包括三個類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的實現
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的實現,包括了put和get方法,還包括了可執行的main函數。
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) {
// 超時對象處理
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.");
}
// 添加緩存對象
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);
}
// 測試入口函數
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);
}
}
}
運行Sample,main函數執行的結果是輸出兩行,第一行為aaa,第二行為null。
china-pub購書網址:http://www.china-pub.com/computers/common/info.asp?id=34017
1、總體感受
a) 這本書主要介紹的是intel平臺下的多核程序設計技術,Windows介紹較多,Linux介紹較少,Java更少。作者是Intel公司的平臺架構師,我們知道wintel聯盟,書中的內容如此分布也是正常。
b) 此書讓我懂得了很多硬件方面的并行知識。
c)
此書介紹Windows API中和并發相關的部分,很詳盡,比Jeffrey
Richter的《Windows核心編成》有深度多了,也精辟多了。顯然《多核程序設計》作者屬于有經驗的工程師,Jeffrey
Richter只是一個寫手,兩者沒有可比性。不過這方面的知識偶早已涉獵,當作復習一遍罷了。
d) 此書偏向底層,硬件和操作系統層面。更高層面的技術介紹較少。
e) 第一次了解OpenMP技術的一些細節。以前只聽說,也沒查過任何相關資料,在此書中看到了相關部分,挺有意思的,感覺那些語法很有趣。Herb Sutter也是要在語法方面動手。反正我在有了一個粗淺認識之后,覺得很有意思。
-------------------------
2、并發流程控制
Fence
在Java
中對應的是java.util.concurrent.CountDownLatch。最初接觸CountDownLatch的時候,由于其實現很簡單,
當時覺得是一個可有可無的工具類。但后來在不同的場景多次使用,發現很有用。在此書中再次發現類似的Fence,用于在共享存儲多處理器或者多核環境中,
確保存儲操作的一致性。我猜這屬于業界并發流控制的典型手段了。
Barrier
在Java中對應的是java.util.concurrent.CyclicBarrier。在應用程序中,一個場景就是和定時器結合使用,countDown、await、reset,做定時定量批量處理。
我猜這也屬于業界并發流程控制的典型手段了。
(CountDownLatch和CycliBarrier的實現代碼都很簡單,但很有用,他們都屬于并發流程控制的典型手段)
-------------------------
3、非阻塞算法
InterLocked在Java中對應的是java.util.concurrent.atomic.xxx
書中提到了cache行乒乓球現象導致的性能問題,提高了非阻塞算法的復雜性問題。
關于性能問題,developerworks上有一片文章,有測試數據:
《Java 理論與實踐: 流行的原子》 (http://www.ibm.com/developerworks/cn/java/j-jtp11234/index.html)
文章中的測試數據表明,直接使用atomic在1個和2個處理器時是最好的,4個處理器以上,使用java.util.concurrent.locks.ReentrantLock性能更好。
java.util.concurrent包,提供了很多高級的概念,隱藏了非阻塞算法帶來的復雜度,其底層框架達到了最佳性能。
-------------------------
4、任務分解、數據分解以及數據流分解
此書中明確提出了這三個概念,很有用,讓我在這方面的知識概念清晰化了。
任務分解
Java
中的Executor,提供了任務分解的手段和模式。任務分解提交給Executor執行。java.util.concurrent中提供了
Future,用于任務提交者和Executor之間的協調。Future是一種很好的手段,在很多涉及并發的庫都提供。例如C++網絡并發庫中提供了
Future,Herb Sutter要在Visual C++中引入Future。
數據分解
數據分解的手段很多也很常見。
Java中,提供了一種高級的數據分解協同模式java.util.concurrent.Exchanger這個類。早在Java SE
5.0時,Exchanger只支持2Parties,Java SE 6.0支持n
parties。偶想象過一些很酷的應用場景,寫過模擬測試,但一直沒有機會用于實際開發中。
數據流分解
書中提到了眾多周知的producer/consumer問題。
其實java.util.concurrent.Exchanger類,既有數據分解,又有數據流分解,exchanger中的producer和consumer的角色會互換的,很有意思。
-------------------------
5、作為Java程序員的思考
Java SE 5.0之后,提供了util.concurrent包,功能齊全,性能卓越,非常優秀。從此書來看,業界流行的流程控制手段和并發程序設計方法一個不落。我們應該感謝偉大的Doug Lea,他為我們帶了一個如此完美的并發庫!
一旦方案想清楚,剩余部分的工作效率瓶頸就在于你的手速了。最近一直看起點中文網上的《師士傳說》,主角葉重一個強項就是手速。
最基本的就是盲打。不會盲打的通常屬于“編碼低能兒”。身邊也有不會盲打的朋友,他們通常都有一個問題,就是眼高手低,說說還行,動手就不行。當然他們能夠在IT研發領域還混得很好,是因為在其他方面擁有優秀的能力。
熟練掌握快捷鍵是關鍵。鍵盤和鼠標之間通常有較大的距離,手經常在鍵盤和鼠標之間移動,會降低效率,也容易導致疲勞,用鼠標過多,也容易導致齷齪的鼠標手。解決這個問題的辦法,就是純鍵盤操作,其實很多IDE的快捷鍵功能強大,足以讓你純鍵盤操作,高效率編碼。
我比較熟悉的IDE是Eclipse,就以Eclispse來說吧。
Eclipse的keys列表中,屬于Eclipse本身有180多個快捷鍵,要提高編碼速度,就應該熟練使用其中絕大多數。
練習的辦法:
1、在Windows/Preferences/General/keys中,使用Export,把快捷鍵導出,導出的格式是csv格式,Windows下可以用Excel直接打開,Linux下可以用OpenOffice打開,打開時選擇分隔符為“,”。
2、挨個練習使用。每天練習一部分,反復練習,堅持一段時間。
3、開始的時候,把鼠標放到一個不方便使用的角落,盡量不要讓自己用鼠標。
4、快捷鍵的組合使用需要加強訓練。在不同場景下,認真考慮用怎樣的組合快捷鍵最高效。
如此堅持一段時間之后,編碼的過程會很流暢,速度就會大大提高。
這是一個很老的問題了,經常在論壇上看到,很多人也寫了相關的文章。我在這方面擁有較多的經驗,我也談一下我的看法吧。
我曾經實現過金蝶EAS BOS的多數據支持引擎,腳本引擎,也作過O-R Mapping的預研工作,曾經對多個O-R Mapping產品做過研究。
C++、Java、C#都源自Algol,這系列語言也稱為Imperative語言,中文翻譯為命令式語言。命令式語言建立在馮*諾依曼體系結構上,程序員必須處理變量管理、變量復制。這樣的結果是增加了執行的效率,但帶來了程序開發的艱苦。
LISP、Schema、Haskell等語言屬于函數式語言,函數式語言基于數學函數,不使用變量或者賦值語句產生結果,使用函數的應用、條件表示和遞歸作為執行控制。函數式語言是更高級的程序設計語言,和命令式語言相比,編寫更少的代碼,更高的開發效率,這是函數式語言的明確有點。很多編程技術都首先應用于函數式語言,例如范型、垃圾收集等。很多函數式語言都增加了一些命令式語言的特征,增加效率和易用性。
SQL語言是一個領域專用語言,專門用于處理關系數據。他具備一些函數式語言的特征,在處理關系數據方面非常直觀和簡介。在處理選擇、投影、聚合、排序等等操作方面,顯然比在Java或者C#中要方便得多。SQL也是易學易用。很多非程序員都掌握SQL,在金蝶,大多需求人員都熟練掌握SQL。SQL的解釋需要損耗一定的性能,在對性能極端要求的情況下,通常不使用關系數據庫。例如Google Account采用Berkeley DB等。
現在關系數據庫已經發展很成熟,數據庫的一些技術發展得很好,包括事務等,其中一些從數據庫中發展起來的技術,還應用到操作系統中了。在前些年面向對象技術狂熱的時候,作了很多面向對象數據庫的研究,但是都沒有取得較大的成功。在主流的關系數據庫中,大多都包括了面向對象的支持,例如Oracle、Sybase,都具備了很豐富的面向對象功能,但是很少任用。
現在有人跟我說起db4o這樣的數據庫,我認為db4o不會取得成功,因為他在錯誤的方向發展。
現在關系數據庫最流行,最流行的應用開發語言包括Java、C#等,都是面向對象命令式語言。開發語言需要訪問關系數據庫,需要轉換,轉換的過程比較繁瑣,于是就誕生了O-R Mapping技術。這是一種妥協的結果,面向對象技術在數據庫領域無法取得成功,在面向對象開發語言中,就需要一種對象-關系映射技術。我相信,這種妥協產生的技術,會越來越流行。
我也認為,這是一個正確的選擇。就如高級語言不會嘗試取代匯編,無論高級語言有多好,最多在其上增加抽象層。例如Java使用bytecode、C#使用IL這樣,使用一種抽象層,而不是嘗試取代匯編。
O-R Mapping技術除了簡單映射之外,需要一種OQL,混合SQL和面向對象特征,提供映射方便的同時,保留關系數據庫提供的強大功能。例如聚合、排序等關系運算必須在OQL中提供。由于程序中的返回結果,有時不需要映射成對象,所以OQL必須提供另外一種功能,數據查詢。很多O-R Mappping產品都提供了基于對象的OQL和基于數據的OQL。
這導致包括三個部分:
1、應用程序使用OQL
2、O-R Mapping解釋或者編譯OQL
3、對象數據庫負責數據處理
如果O-R Mapping使用解釋的方式處理OQL,則會包括產生SQL、組裝對象等操作。效率通常都不會很好,現在的O-R Mapping產品基本都是基于解釋的方式處理。
如果O-R Mapping使用編譯的方式,可以優化產生SQL,動態創建SQL存儲過程,減少SQL交互的過程,能夠獲得很好的性能,可以做到比絕
大多數人直接使用SQL性能都要好。我曾經做過一個實驗性的實現,取得很好的效果,可惜由于種種原因,沒有繼續下去。
我認為,下一代的O-R Mapping產品,都將會采用編譯的方式,因為在很多情形下,特別是復雜對象的處理方面,可以有大幅度的性能提升,在某些場景下,可以數倍甚至數十倍的性能提升。
一直不是很看好Hibernate,因為其主要作者gavin對編譯技術不了解,2.x版本的HQL語法很搞笑,實現也是很搞笑的,簡單的文本替換,看到讓人目瞪口呆。3.0之后加入了HQL的AST(抽象語法樹),但這不是他本人的做的,其他愛好者加入進來,3.1還是沒有很好融合進來。之后的版本我就沒有繼續關注了。
我覺得O-R Mapping完全就是一種編譯技術,不懂編譯技術的人去作這件事清總會有些不妥。這不單是Hibernate的問題,也是其他O-R Mapping產品的問題。
我的觀點:
1、Java、C#、C++等語言在處理關系數據方面沒有優勢。SQL是關系數據處理的領域專用語言(DSL),更適合處理關系數據,提供強大的功能。
2、關系數據是主流,希望應用開發人員使用O-R Mapping,而不懂關系數據庫,這是不現實的。
3、O-R Mapping技術還有很大發展空間,以后在功能、性能等方面都會有重大提升,最終成熟。
文章來源:
http://www.cnblogs.com/jobs/archive/2007/04/23/723297.html
在操作系統中,有兩種不同的方法提供線程支持:用戶層的用戶線程,或內核層的內核線程。
其中用戶線程在內核之上支持,并在用戶層通過線程庫來實現。不需要用戶態/核心態切換,速度快。操作系統內核不知道多線程的存在,因此一個線程阻塞將使得整個進程(包括它的所有線程)阻塞。由于這里的處理器時間片分配是以進程為基本單位,所以每個線程執行的時間相對減少。
內核線程由操作系統直接支持。由操作系統內核創建、調度和管理。內核維護進程及線程的上下文信息以及線程切換。一個內核線程由于I/O操作而阻塞,不會影響其它線程的運行。
Java線程的實現是怎樣的呢?我們通過SUN Java 6的源碼了解其在Windows和Linux下的實現。
在Windows下的實現,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, true, false, 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下的實現,使用_beginthreadex來創建線程,注釋中也說明了為什么不用“Window編程書籍推薦使用”的CreateThread函數。由此看出,Java線程在Window下的實現是使用內核線程。
而在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下的線程的創建,使用了pthread線程庫,而pthread就是一個用戶線程庫,因此結論是,Java在Linux下是使用用戶線程實現的。
MessageDigest的選擇好多,包括MD2、MD4、MD5、SHA-1、SHA-256、RIPEMD128、RIPEMD160等等。我們如何選擇呢?
選擇考慮在兩個方面:安全、速度。
MD2很安全,但是速度極慢,一般不用。
速度方面,最快的是MD4,MD5比SHA-1快
速度排名:MD4 > MD5 > RIPEMD-128 > SHA-1 > REPEMD-160
按照《應用密碼學手冊》提供的表格數據為:
MD4 長度 128 相對速度 1
MD5 長度 128 相對速度 0.68
REPEMD-128 長度 128 相對速度 0.39
SHA-1 長度 160 相對速度 0.29
REPEMD-160 長度 160 相對速度 0.24
我親自測試的結果和《應用密碼學手冊》提供的數據接近。
MD4已經很早證明有缺陷,很少使用,最流行的是MD5和SHA-1,但MD5和SHA1也被王小云找到碰撞,證實不安全。
傳說SHA-1比MD5要安全,但是SHA-1有美國國家安全局的背景,有人懷疑這個算法背后有不可告人的秘密,我也是陰謀論者之一,傾向選擇MD5而不是SHA-1。王小云找到SHA-1碰撞之后,可以說傳說的謠言破滅了,而且MD5速度要比SHA-1快差不多一倍,沒有什么理由選擇SHA-1。
----------------------------------
在Java的現實環境中是怎樣?
在SUN的JCE實現中,只提供了MD2、MD5、SHA-1,SHA-256等常用的MessageDigest算法。
開源的JCE實現bouncycastle則提供了眾多的實現,包括MD整個系列,SHA整個系列,RIPEMD整個系列。
很多的開源項目都帶一個bcprov-jdk14.jar的包,可以說bouncycastle應用很廣泛。SUN公司的一些項目也用了bouncycastle,例如JXTA。
但實際上,SUN的實現包括了MD4,但你需要這樣使用:
MessageDigest md = sun.security.provider.MD4.getInstance();
但是,JDK帶實現性能要比bouncycastle性能好得多,相差速度通常超過一倍以上,我測試過MD5、SHA1和MD4,其性能差別都是類似,一倍多。
比較的結論:
bouncycastle開源免費,提供算法多,但速度較慢
SUN JCE提供的實現,包括了流行常用算法,速度很快,同類型算法比bouncycastle要快一倍以上。
----------------------------------
結論:
又要安全又要速度,選擇MD5
追求安全,不在意速度,相信傳說,不相信陰謀論,選擇SHA系列
追求速度,安全次之,可以選擇MD4。
----------------------------------
現實例子:
emule采用MD4和SHA-1兩種結合使用
apache之類的技術網站,提供下載的文件,同時提供一個校驗文件.md5
不是使用每連接一線程的技術,而是使用多路復用技術。
作了一個分配算法。第一個HTTP Request返回取得ContentLength之后,如果使用多個連接下載,則需要一個分配算法,分配每個Request所對應的Range。分配的部分可能是一個連續的塊,例如bytes=100-999,也可能是一些碎塊,例如bytes=500-600,700-800,850-999。為此,我做了一個數據結構,其提供的功能類似java.util.BitSet,也支持and、or等操作。
實現了對ContentType為multipart/bytes的HTTP Message Body的解釋。如果發送HTTP Request,Range為多個不連續的部分,返回的HTTP Message,就會是multipart,每個part都會包括一個Head和一個Body,需要一個解析器。
下一步就是把HTTP下載加入P2P下載中!
最近編碼更流暢了。原因包括:
1) 絕大多數時候純鍵盤操作,Eclipse 200多個快捷鍵,我熟練使用絕大部分,編碼的過程,如同行云流水般。
2)掌握了更多的解決問題的辦法,有了更廣的知識面,編碼時,信手拈來。最近一年里,掌握了很多知識,包括并發、網絡、操作系統等等方面的知識。
3)組織代碼的能力更強了,最近對于大型復雜的程序,組織代碼的能力更強了,組織程序的能力包括,更好的結構,更好的擴展性,可測試性,可管理性等等。
a) 在編碼的過程中,使得更多的模塊可以單獨于整個環境獨立測試
b) 精心處理過的LOG,使得代碼更容易跟蹤,排錯。
c) 復雜的模塊,附帶監控管理界面,使得排錯和優化都更為方便。
d) 使用制作狀態轉換表的手段,清晰化復雜的狀態處理。在前些年設計/實現工作流引擎時,就開始使用狀態轉換表描述狀態機,但現在面臨的狀態機復雜。
貼圖的實現方式為:
1、把剪切板中的圖片存在本地的SendingImages目錄,存放的格式使用PNG,當然可以其他格式,但是PNG格式更小。
2、使用MD5算法產生一個ImageID。當然可以使用SHA1等其他算法
3、把imageID發送remote peer
4、當remote peer收到imageID時,檢查本地ReceivedImage目錄,如果已經存在,顯示圖片,不存在則發送一個RequestImage請求,并在聊天記錄中顯示一個等待信息(為一個GIF動畫)。
5、本地Peer收到RequestImage請求之后,發送圖片數據。如果圖片大于64K,則分塊發送。
6、remote peer收到圖像數據之后,進行校驗,看是否正確。
7、校驗通過后,把圖片在聊天面板上顯示(替換等待圖片)
預定義表情的實現很簡單,自定義表情的實現和貼圖實現一致,只是少了從剪貼板保存圖片的過程。
上一篇博客寫了我一些關于P2P下載以及平臺的思考,有這樣的思考,是因為我正在做一件這樣的事情。
我介紹一下我正在做的事情吧:
1、基于JXTA,我崇拜Bill Joy,學習JXTA就是因為我崇拜他,之后覺得這個技術很棒。但是JXTA存在一些用戶不友好的地方,包括JXTA的ConfigDialog和DialogAuthenticator是十分用戶不友好的,我重寫了這些部分。雖然是一些無關痛癢的地方,但是可以改變用戶體驗,提高用戶友好性。
2、簡單的插件機制,我做了一個簡單的插件系統,Application啟動之后挨個裝載服務,UI也是服務之一,UI也是基于插件的,在微內核框架流行的今天,使用一個簡單的插件機制似乎不是太好,等過一段時間之后考慮使用osgi替代之。
3、提供了兩個功能,聊天和文件共享下載。這兩個功能分別表現為兩個JXTA的Service。
4、聊天功能。目前還比較簡單,只實現了不帶格式的文本聊天,但是我隨后會加入帶格式的文本聊天,也將會加入類似騰訊QQ那樣的貼圖支持,自定義表情支持,騰訊QQ的實現很巧妙,但并不困難。四月初的版本就有可能實現之。
5、共享和下載。目前實現了文件和文件夾的共享。其中包括了高級智能錯誤檢測(AICH)等。傳輸協議參考了BT和emule的協議。在界面中還實現對DragAndDrop支持,從Windows Explore中拖一個文件到目錄共享的面板,即開始共享該文件。
6、存儲信息采用apache的Derby數據庫。我很喜歡Berkeley DB,Berkely DB高效簡潔,但是License不開放。我最終還是采用Derby了,采用Derby將會帶來一系列好處,SQL支持、JDBC支持等等,License無限制等等。擴展的應用基于其上也十分方便。由于我曾經開發過多數據庫支持引擎KSQL,在KSQL上增加支持Derby的翻譯是很容易的事情。如此一來,可能存儲引擎部分,將有可能擴展到KSQL目前所支持的多種數據庫,包括嚴格測試過的Oracle、DB2、MS SQL Server,還有經過簡單測試支持Sybase、PostgreSQL、MySQL。
7、最近的JXTA Java SE 2.5版本,使用了nio來管理連接,也就說,使用了多路復用的技術,使得每個Peer創建大量連接成為可能,例如Windows下默認最大的多路復用支持1024個連接。而Linux下,java nio是使用epoll實現的,并發性能將更好,這對于聚合點來說很重要。普通的Peer部署在Linux下可能較少,但是聚合點部署在Linux完全是可能的。
8、使用Swing做界面,使用Java 6 SE的Swing,做了系統托盤Tray的支持等等。由于Swing的UI設計工具很不穩定,最終完全手工編寫UI部分代碼,雖然辛苦,但是代碼簡潔,不同UI Designer生成的那樣。
9、我期望4月初發布一個版本,提供一個基本可用的版本。
10、我是從1月初開始學習JXTA的,到現在還不滿3個月,其中還包括過年回家休息等等,玩游戲沉迷等等,但總的來說,我對這個學習速度很滿意。不過其中感覺最爽的是,在這個過程中,編碼時,基本純鍵盤操作,不用鼠標,如行云流水一邊,十分流暢,工作效率高,人也舒服。
1、使用多路復用或者異步I/O模型,這本是服務器段常用的技術,但在P2P應用,每臺機器既是服務器,又是客戶端,共享了一個十分受歡迎的文件,可能會有很多希望連接者,或者你下載一個受歡迎文件時,可能搜索到數百上千的Peer,此時就很有必要采用多路復用或者異步I/O技術,降低應用程序所占用的資源。
2、支持傳統的協議,包括HTTP和FTP,其實這兩種技術能夠和P2P網絡集成,其中一種辦法就是,在提供下載地址的同時提供一個種子文件下載,例如服務器中提供了ABC.rar文件,同時提供一個ABC.rar.md5文件允許下載,這樣P2P下載工具下載時,通過md5在P2P網絡中搜索更多的資源,這樣客戶能夠獲得更好的速度,服務器端也可能降低下載的網絡流量。
3、流行的P2P網絡協議支持,包括BT和emule,這兩種都是公開協議了,都有開源的實現,可以參考并重寫,要支持并不困難。
4、健壯性。如同emule一樣,將文件分塊(piece)的同時,把每一塊摘要一個piece_ID,將所有的piece_ID再摘要成一個總的ID,成為AICH。其實這也是一種很簡單的技術,實現起來并不困難,做法可以多種多樣。
5、對大型局域網有特別支持。現實中,存在很多大型的局域網,局域網之間的擁有高速的帶寬。對局域網的特別支持辦法也有很多的,例如,類似BT那樣,在局域網里建立一個Tracker Server。若是基于JXTA,可以在局域網里部署聚合點(Rendezvous)
6、支持P2P目錄共享,現在流行的P2P下載工具,都不支持以目錄為單位實現P2P共享和下載。其實支持P2P目錄共享也不困難,在提供共享時,提供一個目錄結構信息就可以了。目錄結構信息dir_info可以這樣記錄:子文件或子目錄路徑 偏移量 長度。當然把目錄壓縮然后提供下載也是可以的,不過這樣會浪費共享者的磁盤空間。目錄共享,要考慮共享之后文件進行修改,添加新文件等事情,使用dir_info能夠更好解決這種問題。
7、關于通告。一個P2P共享資源(包括文件和目錄),應該包括三個ID:content_id、aich_id、dir_info_id。其中content_id是整個資源的摘要,aich_id是每塊id進行摘要產生的id,dir_info_id是dir_info的摘要id。
content_id可用資源搜索,建議采用MD5摘要產生,因為現在很多網上提供下載的文件,都提供一個.md5后綴的校驗文件。
aich_id用于校驗和智能恢復
dir_info_id。如果計算content_id時,dir_info獨立計算,則需要提供dir_info_id,用于校驗dir_info。理論上dir_info可以作為content的一部分,但是我覺得dir_info獨立計算會帶來很多好處。
8、關于傳輸。資源的傳輸,應該包括三部分,hashset的傳輸、dir_info的傳輸、內容數據的傳輸。內容傳輸是分塊傳輸的,我覺得采用BT的默認值256K一塊挺好的。每一塊(piece)摘要計算一個piece_id,所有的piece_id放在一起,就是一個hashset,hashset這個名字不大好,不直觀,但既然emule協議是這樣會說,我也這樣說好了。dir_info是可選的,文件共享不帶dir_info。
9、P2P下載技術的應用范圍應該擴展,程序的安裝更新都應該加入P2P的支持,將會大大提高程序的用戶體驗。
10、P2P的平臺應該具備良好的擴展性。當我們構建起一個龐大的P2P平臺時,不單單只是在其上共享文件,有很多應用可以部署在其上,包括現在很流行的P2P視頻,分布式計算等等。即時通訊也是可以構建在P2P網絡上的。面對眾多的應用需求,我們需要一個具備良好擴展性的協議,不應該像BT和emule那樣,除了下載,別無它用。可能基于JXTA是一種較好的選擇。
11、安全。P2P網絡應該支持安全特性,一些團體,一些企業,需要限定范圍內共享資源。例如NASA的衛星數據共享項目SAXTA,采用JXTA,就是因為JXTA支持安全特性。我想很多的P2P應用場景,都需要安全,例如,企業只希望內部員工之間實現P2P資源共享等等。
1、通用的唯一ID,使用MD5或者SHA1等摘要算法。
2、需要引入類似emule AICH機制,防止惡意客戶端搗亂,或者用戶修改數據之后,無意上傳錯誤數據。
3、引入文件結構。描述文件在整個共享內容中的位置,整個共享項包括那些文件等等。
4、總共的ID應該包括:唯一ID、AICH_ID、文件結構摘要三個。如果使用JXTA的方式,需要在ContentAdv中包括這三個ID。
5、如果采用類似BT種子文件的方式,可以把三個ID、AICH_HashSet、FILE_LIST_INFO全部放在一起。
在做一個基于JXTA的實現,當然支持目錄P2P共享的,已經實現的差不多了,自我感覺很酷!!
jxta.org上也有一個資源共享的項目,jxta-cm,但是這個項目作的不夠好。
我重新設計了傳輸協議,參考了BT的傳輸協議。
存儲本地信息,不像jxta-cm那樣簡單,序列化一個本地磁盤文件,而是引入了Derby數據庫。我本想用Berkeley DB的,我很喜歡Berkeley DB,但是由于版權協議的問題,不得不放棄了。
當然與jxta-cm還有其他很多地方不同,包括一邊下載一邊上傳等等。
今天文件傳輸測試成功了,隨后將會進行更多的測試,保證穩定。
希望4月1日能夠出一個愚人節版本。
Java SE 6.0的改變包括了ClassFile格式的改變。
新的版本的ClassFile中major_version為0x0032,也就是50。
Java SE 6 : 0x0032?? (用自己寫的ClassFileParser分析過證實)
Java SE 5 : 0x0031??(用自己寫的ClassFileParser分析過證實)
JDK 1.4?? : (未經證實是0x0030)?
JDK 1.3?? :? (未經證實是0x002F)
JDK 1.2?? : 0x002E
JDK 1.1?? : 0x002D??
每次JDK大版本升級,ClassFile格式都改變,然后版本加1。
6.0增加了StackMapTable的Attribute。
要提一下三個byte code處理庫:
ObjectWeb ASM
Apache BCEL
sourceforge SERP
ASM目前版本為3.0。其2.1版本開始支持StackMapTableAttribute。
其中ASM 2.1支持StackMapTableAttribute,BCEL 5.2似乎只支持JDK 1.3,SERP 1.12只支持JDK 5.0。
Aapche BCEL支持JDK 1.3,是從代碼中猜測的,沒有從文檔中看到,但其中5.2版本的ClassParser的確是不支持StackMapTable Attribute,其代碼中的StackMap和Java SE 6.0的StackMapTable Attribute沒有任何關系。BCEL中的對象和ClassFile中的各項對應,用于學習分析方便。
ASM號稱更小,速度更快。現在流行的Eclipse插件bytecode outline也是其中的子項目。
ASM可以直接cvs訪問,提供的代碼是一個Eclipse Project,十分方便,我很喜歡!
http://forge.objectweb.org/projects/asm/
在規范4.10.1中的這一段話有些疑問:
If the class file version number is 51.0 or above, then neither the jsr opcode or the jsr_w opcode may appear in the code array.
class file version number is 51.0 or above,什么意思?Java SE 6.0編譯出倆的結果應該是50.x,這是怎么回事?
規范是一個186頁的PDF,沒有文檔大綱,看暈了
這是6.0之前的poll模型。
solaris\native\sun\nio\ch\SocketChannelImpl.c
JNIEXPORT?jint?JNICALL
Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv?*env,?jobject?this,
???????????????????????????jobject?fdo,?jboolean?block,
???????????????????????????????????????????????jboolean?ready)
{
????int?error?=?0;
????int?n?=?sizeof(int);
????jint?fd?=?fdval(env,?fdo);
????int?result?=?0;
????struct?pollfd?poller;
????poller.revents?=?1;
????if?(!ready)?{
????????poller.fd?=?fd;
????????poller.events?=?POLLOUT;
????????poller.revents?=?0;
????????result?=?poll(&poller,?1,?block???-1?:?0);
????????if?(result?<?0)?{
????????????JNU_ThrowIOExceptionWithLastError(env,?"Poll?failed");
????????????return?IOS_THROWN;
????????}
????if?(!block?&&?(result?==?0))
????????return?IOS_UNAVAILABLE;
????}
????if?(poller.revents)?{
????????errno?=?0;
????????result?=?getsockopt(fd,?SOL_SOCKET,?SO_ERROR,?&error,?&n);
????????if?(result?<?0)?{
????????????handleSocketError(env,?errno);
????????????return?JNI_FALSE;
????????}?else?if?(error)?{
????????????handleSocketError(env,?error);
????????????return?JNI_FALSE;
????????}
????????return?1;
????}
????return?0;
}
6.0缺省的模型是使用epoll
E:\Java\jdk-6-rc-src\j2se\src\solaris\native\sun\nio\ch\EPollArrayWrapper.c
JNIEXPORT?void?JNICALL
Java_sun_nio_ch_EPollArrayWrapper_init(JNIEnv?*env,?jclass?this)?
{
????epoll_create_func?=?(epoll_create_t)?dlsym(RTLD_DEFAULT,?"epoll_create");
????epoll_ctl_func????=?(epoll_ctl_t)????dlsym(RTLD_DEFAULT,?"epoll_ctl");
????epoll_wait_func???=?(epoll_wait_t)???dlsym(RTLD_DEFAULT,?"epoll_wait");
???????????????????????????????????????????????????????????????????????????????????????????????????
????if?((epoll_create_func?==?NULL)?||?(epoll_ctl_func?==?NULL)?||
????????(epoll_wait_func?==?NULL))?{
????????JNU_ThrowInternalError(env,?"unable?to?get?address?of?epoll?functions,?pre-2.6?kernel?");
????}
}
具體程序的流程我還是不夠清楚,還有待進一步深入了解。
java 1.4提供了nio,也就是之前我的一片博客中所說的multiplexed non-blocking I/O。這種模型比阻塞模型的并發性能要好一些,Java很多的網絡應用都因此重寫了底層模塊,包括Tomcat、Jetty等等,也出現了基于nio的框架mina、國產的cindy等等。
java nio帶來的影響是巨大的,得到了很多擁護和贊賞。
不過有一些是謠言,例如windows下的實現是Windows中并發性能最好的I/O模型IOCP,但事實上是這樣么?
JDK 6.0 RC版提供了源碼下載,下載路徑:
http://www.java.net/download/jdk6/jdk-6-rc-src-b104-jrl-01_nov_2006.jar我們看最終Windows的實現:
j2se\src\windows\native\sun\nio\ch\WindowsSelectorImpl.c
82行開始:

????/**//*?Call?select?*/
????if?((result?=?select(0?,?&readfds,?&writefds,?&exceptfds,?tv))?

?????????????????????????????????????????????????????????????==?SOCKET_ERROR)?
{

????????/**//*?Bad?error?-?this?should?not?happen?frequently?*/

????????/**//*?Iterate?over?sockets?and?call?select()?on?each?separately?*/
????????FD_SET?errreadfds,?errwritefds,?errexceptfds;
????????readfds.fd_count?=?0;
????????writefds.fd_count?=?0;
????????exceptfds.fd_count?=?0;

????????for?(i?=?0;?i?<?numfds;?i++)?
{

????????????/**//*?prepare?select?structures?for?the?i-th?socket?*/
????????????errreadfds.fd_count?=?0;
????????????errwritefds.fd_count?=?0;

????????????if?(fds[i].events?&?POLLIN)?
{
???????????????errreadfds.fd_array[0]?=?fds[i].fd;
???????????????errreadfds.fd_count?=?1;
????????????}

????????????if?(fds[i].events?&?(POLLOUT?|?POLLCONN))?
{
????????????????errwritefds.fd_array[0]?=?fds[i].fd;
????????????????errwritefds.fd_count?=?1;
????????????}
????????????errexceptfds.fd_array[0]?=?fds[i].fd;
????????????errexceptfds.fd_count?=?1;


????????????/**//*?call?select?on?the?i-th?socket?*/
????????????if?(select(0,?&errreadfds,?&errwritefds,?&errexceptfds,?&zerotime)?

?????????????????????????????????????????????????????????????==?SOCKET_ERROR)?
{

????????????????/**//*?This?socket?causes?an?error.?Add?it?to?exceptfds?set?*/
????????????????exceptfds.fd_array[exceptfds.fd_count]?=?fds[i].fd;
????????????????exceptfds.fd_count++;

????????????}?else?
{

????????????????/**//*?This?socket?does?not?cause?an?error.?Process?result?*/

????????????????if?(errreadfds.fd_count?==?1)?
{
????????????????????readfds.fd_array[readfds.fd_count]?=?fds[i].fd;
????????????????????readfds.fd_count++;
????????????????}

????????????????if?(errwritefds.fd_count?==?1)?
{
????????????????????writefds.fd_array[writefds.fd_count]?=?fds[i].fd;
????????????????????writefds.fd_count++;
????????????????}

????????????????if?(errexceptfds.fd_count?==?1)?
{
????????????????????exceptfds.fd_array[exceptfds.fd_count]?=?fds[i].fd;
????????????????????exceptfds.fd_count++;
????????????????}
????????????}
????????}
????}????????????這就是廣泛應用在Winsock中使用的select模型,也眾所周知,并發性能不是很好。而且FD_SETSIZE不能超過Windows下層提供者的限制,這個限制通常是1024。也就是說Windows下,JDK的nio模型,不能超過1024個連接,這個跟我之前做的測試結果相似。
而且,如果FD_SETSIZE很大的話,例如是1000,調用select之前,必須設置1000個socket,返回之后又必須檢查這1000個socket。
也就說,Windows下使用SUN JDK java的nio,并不能提高很好的并發性能。
回顧一下Unix的5種I/O模型
1、阻塞I/O
2、非阻塞I/O
3、I/O復用(select、poll、linux 2.6種改進的epoll)
4、信號驅動IO(SIGIO)
5、異步I/O(POSIX的aio_系列函數)
同步I/O和異步IO
POSIX把這兩個術語定義如下:
同步I/O操作導致請求進程阻塞,直至操作完成
異步I/O操作不導致請求阻塞。
根據上述定義,前四種I/O模型都是同步I/O,第5種才是異步I/O。
select不允許多于一個的線程在同一個描述符集上等待。這使得反應式模型不適用于高性能應用,因為它沒有有效地利用硬件的并行性。
異步I/O通常能夠提高更好的性能,windows的iocp通過內核線程調度,也能提供很好的并發性能,但不是真正的異步。
Java nio和多路復用
java 1.4 nio提供的select,這是一種多路復用I/O(multiplexed non-blocking I/O)模型,底層是使用select或者poll。I/O復用就是,阻塞在select或者poll系統調用的某一個之上,而不是阻塞在真正的I/O系統調用之上。JDK 5.0 update 9和JDK 6.0在linux下支持使用epoll,可以提高并發idle connection的性能(
http://blogs.sun.com/alanb/entry/epoll)。
以前看到有人猜測Windows下nio使用了IOCP,那應該是錯的,畢竟IOCP不是多路復用I/O模型。從JavaOne 2006的幻燈片來看,aio才會使用IOCP來實現的。
Java aio和JSR 203
2003年,就有了JSR 203(
http://jcp.org/en/jsr/detail?id=203),但是一直沒有實現。
終于,JSR 203的spec lead說,將會在Java SE 7.0中完成JSR 203,Java SE 6.0已經是RC,很快正式版就會發布,然后就是Java SE 7.0,估計我們不需要等太久了。
http://blogs.sun.com/alanb/entry/what_is_happening_with_jsrasynchronous I/O對于Java的影響,將不會低于當年JDK 1.4 nio引入multiplexed non-blocking I/O的影響,很多的Java應用都會重寫。如同Linux 2.6支持AIO,DB2、Oracle數據庫都會發布新版本,說支持使用AIO,性能提高多少多少云云(主要是AIO的文件操作部分)。
對asynchronous I/O的支持,Java程序就能夠支撐大并發網絡應用了,在IO模型方面,對于C/C++等語言不再存在“C/C++能做,但是Java不能做的事情”。
這個是Java One 2006上的幻燈片。
http://blogs.sun.com/roller/resources/alanb/bof0895.pdf提到了:
需要新的channel types支持異步I/O模型
使用Native機制,例如Windows IO Completion ports。
文章:
http://blogs.sun.com/alanb/entry/epoll
JDK 6.0 nio支持epoll,對并發idle connection會有大幅度的性能提升,這就是很多網絡服務器應用程序需要的。
One of the updates in build 59 of
Mustang
(Java
TM SE 6)
is that the New I/O
Selector
implementation will use the
epoll event notification
facility when running on the Linux 2.6 kernel.
JDK 5.0 update 9也支持了。
The epoll SelectorProvider will be included in 5.0 update 9. To enable
it requires setting the system property
java.nio.channels.spi.SelectorProvider to the value
sun.nio.ch.EPollSelectorProvider.
5種IO模型:
阻塞IO
非阻塞IO
多路復用
信號驅動IO
異步IO
最好性能的還是異步IO,目前Java只能支持到多路復用一級,期待著以后Java 7.0/8.0支持異步IO,6.0是沒有希望了。
買了個新硬盤安裝ubuntu,把所有的工作遷移到linux下進行。
沒感到什么不方便的,畢竟最常用的工具是Eclipse、Firefox、UltraEdit。UltraEdit在linux下的替代品為vi和gedit,一切都好。
聽音樂的播放器要比windows下要差一些,也沒關系,將就著用。
字體有些難看,也能用,可以將就。
開發環境,在Ubuntu下配置ACE、boost等庫的環境是在太方便的,比windows下方便多了。
唯一的缺陷就是系統不穩定,用linux作服務器是很穩定的,但是linux的桌面系統穩定性就比較差勁了,仿佛回到
windows 98的那種年代,系統經常死機。
總之,了系統不穩定之外,一切都好。

文章來源:
http://www.cnblogs.com/jobs/archive/2006/10/25/538989.html
一直以來,都是使用兩種即時通訊工具QQ和MSN,最近越來越討厭MSN,而覺得QQ越作越好。
1、MSN是明文傳輸數據,偷窺、監聽都是極為簡單的事情。查看別人MSN是某些網管的樂趣,而且是普遍的現象。
2、MSN任何時候的聊天數據都是明文經過服務器的,這個動機非常值得懷疑。明文傳輸而且通過服務器,為了使得海量監聽更有效率?
3、MSN在貼圖、群方面功能缺乏,聊天記錄沒有等等,不好用,不方便。
4、騷擾很多,一些交友網站的騷擾煩死人。
5、MSN的語音傳輸效果很差,而且經常建立不了連接。
6、文件傳輸很慢。
QQ雖然也不是極好,但比MSN還是強一些。
1、QQ聊天數據傳輸是使用TEA加密的,雖然并不是非常高強度的加密,但至少是經過加密的。
2、QQ聊天數據,雙方都在線的時候,不經過服務器。如果對方不在線,聊天記錄經過服務器,會受到監聽審查。但比MSN要好一些。
3、QQ功能比MSN完備,使用方便。
這兩種工具的官方版本都是廣告一大堆,解決辦法就是使用第三方的客戶端。例如lumaQQ、gaim來替代他。
在中文世界中,越來越多人使用QQ,包括一些海外的朋友,終有一天在中文世界里,MSN就如ICQ一樣,微不足道,這是一個可以預見的趨勢,我也將很樂見看到這個結果。
因為還有一些朋友只使用MSN,現在只能是少用MSN,最終將會不再使用MSN。

文章來源:
http://www.cnblogs.com/jobs/archive/2006/11/08/553714.html
Herb Sutter的觀點
Herb Sutter最近的一篇文章中如是說:“90年代,我們到處跟人叫講,什么是對象,什么是虛函數,現在我們到處跟人說,什么是主動對象,什么是Future”,他還說,結構編程、面向對象,現在該輪到并發和并行了。
記得在去年,Herb Sutter就寫文章預示并發時代的到來,主要是因為CPU的主頻將不再會有以前那樣的增長速度,而將迎來多核時代。程序將是靠并發來提高運行效率。
JDK 1.5 Concurrent包
在傳統的多線程程序中,經常會有:
創建線程
wait\notify
重新發明輪子,例如BlockingQueue、Lock、Semaphore這樣的基本工具類。
不恰當的抽象,會導致難以承受的復雜度,代碼錯誤多,常犯死鎖、lost notify之類,也很容易導致性能低下。我也有過這樣的經歷,失敗的教訓刻骨銘心。
JDK 1.5 util.concurrent包提供了一系列工具類,其中一些類的使用,代表一些觀念的轉變,更好的抽象,優雅的設計模式,會使多線程程序具有良好的結構。
使
用Excector、ScheduleExecutorService、Future、BlockingQueue等類搭建起來的程序,會使得多線程程序
有很清晰明了的結構。其中的差別,似乎就象以前“非結構化程序設計”到“結構化程序設計”那樣的轉變,現在我們使用Future等設計模式,起到了同樣好
的效果。
結構化程序設計,使用if/else、while、do...while、for、switch等結構,把程序組織的清晰易懂,更容易掌握,更少出錯。
Executor、Future、Concurrent Collection等工具類、模式,使得并發程序結構清晰化/模式化,更容易掌握,更少出錯,也更高效。
隨著多核CPU的普及,摩爾定律逐步失效,并發程序設計將會是程序員要求掌握的基本技巧,就如同現在程序員要求掌握面向對象一樣。
有幾個文檔值得一看的:
javaone的幻燈片
http://developers.sun.com/learning/javaoneonline/2005/coreplatform/TS-3423.pdf
http://developers.sun.com/learning/javaoneonline/2005/coreplatform/TS-5807.pdf
Doug Lea的文章
http://gee.cs.oswego.edu/dl/papers/aqs.pdf
上面的文檔只能給你一個介紹,最好的辦法還是通讀一遍JDK 1.5 utilconcurrent包的源碼,然后在實踐中,改變觀念,積累經驗。
并發和網絡編程
網
絡中,存在中心服務器,不同機器的交互,并發和異步是常見行為。網絡中的服務器,需要相應大量的并發,這種并發通常會是極端的并發,操作系統提供一些特別
的API,例如select模型,poll,windows的完成端口等等。JDK在1.4之后支持nio,主要也是針對大并發的支持。
C++的框架ACE,提供了跨平臺的線程、進程、Future等API,并且提供了Reactor、Proactor等框架,使得能夠容易編寫跨平臺的并發網絡服務器。
ACE框架的一個思想就是,使用ACE和模式消除復雜性。這一點和JDK 1.5 concurrent包提供的高級設計模式類的意圖是一致的。
在《C++網絡編程》卷1和卷2中講述了一些模式,例如Half Sync/Aysnc vs Leader/Follow模式。這是ACE開發過程中的一些研究成果,我們查找ACE相關資料時,會發現一些關于并發方面的論文。ACE也提供了Future。
我才運用ACE作了一些簡單的應用,了解還不夠深入,不過覺得JDK concurrent包在并發設計模式方面,比ACE走到更遠。
今天,你使用Future了嗎?

文章來源:
http://www.cnblogs.com/jobs/archive/2006/11/10/556063.html
并發程序設計的領域,有三個牛人
Doug Lea (Java util.concurrent)
Douglas C. Schmidt (ACE、POSA2)
Herb Sutter (C++/CLI concurrent)
Doug Lea

util.concurrent包的作者,JSR166規范的制定。圖書著作《Concurrent Programming in Java:
Design Principles and Patterns》。在JDK
1.6的源碼中,還看到他修改的代碼(例如重寫Exchanger,修正N parters時死鎖的問題)。隨著JDK
1.5、1.6的普及推廣,他的思想,他的作品,都將產生極大的影響。
Douglas C. Schmidt

他創造了ACE,一個流行開源跨平臺的C++網絡框架。他的圖書著作:
《C++ Network Programming: Mastering Complexity Using ACE and Patterns》
《C++ Network Programming: Systematic Reuse with ACE and Frameworks》
《Pattern-Oriented Software Architecture: Patterns for Concurrent & Networked Objects》
他的成果:
Leader/Follow模式
ACE Reacotr
ACE Proactor
雖然ACE中也包括Acitve Object、Future等,他的書中也講述了基于事件/基于任務的模型,但這些并非他的創造。
Douglas C. Schmidt的成果是網絡、并發、跨平臺。
Douglas C. Schmidt創造輝煌的時刻已經過去了。
Herb Sutter

ISO C++標準委員會主席,微軟C++/CLI首席架構師,Exceptional三卷書的作者,目前領導微軟的concur
Project。從2005年開始,他一直發表一些預告并發時代來臨的文章。2005年,他代表Microsoft參加OOPSLA,主題就是關于C++
/CLI的并發。Herb Sutter是我極為敬仰的牛人!
他的網站:
http://www.gotw.ca/

文章來源:
http://www.cnblogs.com/jobs/archive/2006/11/10/556470.html
C++領域的知名人物
Bjarne Stoustrup 一代宗師,發明了C++,并且作了第一個實現,把面向對象技術帶入主流,豐功偉業啊。
Herb Sutter 大師 (IOS/ANSI C++標準委員會秘書,目前領導微軟的Concur Porject,推動并發進入主流,有成為宗師的潛力)
Andrei Alexandrescu 牛人 (經典著作《Modern C++ Design Generic Programming and Design Patterns Applied》)
Lippman 牛人 (寶刀已老)
Scott Meyers (著名講師,自吹為C++領域權威,著作為Effetive C++系列)
侯捷 (著名譯者,翻譯的書質量不錯,但他寫的書千萬別買)
上面的排名分先后.
Herb Sutter
我最佩服的人之一,他寫的Exceptional C++系列三卷書,他的網站www.gotw.ca,OOPSLA上的演講,他在微軟的C++/CLI、Concur Projec等,最近兩年所寫的關于并發的一些列文章,都是非常非常的棒,偶像啊!!


有胡子的照片比較帥一些。
Bjarne Stoustrup
他來過中國,以前的照片是有胡子的,好酷,最近他網站的照片胡子刮干凈了,難道是為了顯得年輕一些么?

Lippman
很明顯,他已經老了。
Scott Meyers

這就那個說自己是C++領域權威的家伙(真的是嗎?)

文章來源:
http://www.cnblogs.com/jobs/archive/2006/11/11/557511.html
昨天就開始看這個PPT,看了幾遍,對并發的前景有了更多的理解。
http://irbseminars.intel-research.net/HerbSutter.pdf可以從他的網站上下載視頻版本。
過去30年,主流軟件開發一直忽略了并發。但是現在,并發時代要來了,因為我們的新電腦是并發的,軟件開發將會迎來巨變。
現在買的電腦,是雙核的,明年就會是4核,然后就是8核,16核,32核……,都是之后幾年的事情,一切都不遙遠!

很多服務器程序準備好了(也不完全是吧),而客戶端程序還沒有。

算法的時間復雜度改變了

盲人摸象

技術發展史
|
出現 |
進入主流 |
GUIs |
1973 (Xerox Alto) |
~1984-89 (Mac)
~1990-95 (Win3.x) |
Objects |
1967 (Simula) |
~1993-98 (C++, Java) |
Garbage Collection |
1958 (Lisp) |
~1995-2000 (Java) |
Generic Types |
1967 (Strachey) |
~198x (US DoD, Ada) ~1995-2000 (C++) |
Concurrency |
1964 (CDC 6600) |
~2007-12 (est.) |
他的PPT中還講述了Acitve Object、Future、Atomic之類的,VC提供特別語法支持。這也是老生常談的咚咚了。

文章來源:
http://www.cnblogs.com/jobs/archive/2006/11/12/558078.html
一般來說,Exchanger都是一個Consumer,一個producer,在適當的時候互相交換,這樣可以避免鎖。
我想到Exchanger N parties的一種用法。如下:
最初N個都是producer,達到一定條件之后,進行交換。根據交換的結果重新確定角色,決定自己是consumer還是producer。
這樣做的結果是,最初所有都是producer,之后一部分轉變成consumer。并且由于consumer以及producer的速度不一樣,而能夠自動適應調整。
要注意的是,JDK 1.5中的Exchanger只支持2 parties,N parties時,N > 2會導致死鎖。JDK 1.6中,Exchanger重寫了,沒有這個問題。
在JDK 1.5中要這樣用的話,可以把JDK 1.6中Exchanger源碼抄過來就是了。

文章來源:
http://www.cnblogs.com/jobs/archive/2006/11/12/558626.html
java.util.concurrent中的ExecutorCompletionService,其實現的是CompletionService接口。
我對ExecutorCompletionService存在一個疑問,在其實現中,task是被執行之后,才把futureTask加入到completionQueue,既然如此,不如直接把Result加入到completionQueue中了。這個行為沒什么差別的。對這個類的設計存在一些懷疑,我認為其task方法,似乎返回值是V更合適。
原來是這樣的:
Future<V> take() throws InterruptedException;
Future<V> poll();
覺得也許應該改稱這樣:
V take() throws InterruptedException;
V poll();

文章來源:
http://www.cnblogs.com/jobs/archive/2006/11/13/559609.html
客戶端程序應用
無意發現的一個類
package javax.swing;


public abstract class SwingWorker<T, V> implements RunnableFuture<T>
{ }
也就是,一些并發相發的設計模式,已經應用在客戶端程序設計中。
我沒有對swing關注更多,只是覺得預想中的趨勢開始出現了。
Exchanger
重寫了,支持N parties。
RunnableFuture
這是理所當然的事情,Executor使用之后,FutureTask這個東西常用,兼有Runnable和Future,所以出現一個RunnableFuture是理所當然。
ConcurrentNavigableMap
一些系列的派生類,例如ConcurrentSkipListMap等等,還沒用過,大概就是一個并發支持的SortedMap了。

文章來源:
http://www.cnblogs.com/jobs/archive/2006/11/14/559859.html
應該來說,util.concurrent包中提供的atomic,包括兩部分:
1、atomic值對象,例如AtomicInteger、AtomicLong等。常用作計數器。
2、AtomicReference
3、一些內部使用Lock提供的compareAndSet操作。例如ConcurrentHashMap的putIfAbsent。
.NET中也提供了類似的功能,InterLocked類提供著完全的能力。
這是一種思想,提供原子操作,把兩個以上的操作合并,使得調用者不需要使用Lock,使得程序結構變得簡單,減少出錯的可能,包括減少死鎖發生的可能,程序也因此獲得更好的性能。
將會有更多的數據結構支持atomic操作,JDK 1.5提供了支持atomic操作的ConcurrentMap、JDK 1.6提供了支持atomic的ConcurrentNavigableMap。
如同Herb Sutter預測的那樣,并發技術將進入主流,這個過程會持續數年。

文章來源:
http://www.cnblogs.com/jobs/archive/2006/11/14/560416.html