新寫了一個Java并發(fā)程序設(shè)計教程, 用于公司內(nèi)部培訓(xùn)的,和2007年寫的那個相比,內(nèi)容更翔實一些。
內(nèi)容列表
1、使用線程的經(jīng)驗:設(shè)置名稱、響應(yīng)中斷、使用ThreadLocal
2、Executor :ExecutorService和Future ☆ ☆ ☆
3、阻塞隊列 : 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)驗介紹
7、并發(fā)流程控制手段:CountDownlatch、Barrier
8、定時器: ScheduledExecutorService、大規(guī)模定時器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
Google云計算AppEngine
Java版剛剛推出來的時候,我就申請了該服務(wù)。該服務(wù)的申請需要提供手機號碼驗證,GOOGLE很牛B,能夠發(fā)送全球的手機短信。申請的帳號放了很久,
前段時間學(xué)習(xí)OpenID,需要作一個范例,于是就在Google
AppEngine上作,作的過程發(fā)現(xiàn)其不能使用線程,導(dǎo)致HttpClient組件無法工作,于是我修改了OpenID4Java的實現(xiàn),全部使用
URLConnection來實現(xiàn)。最終程序部署成功了,網(wǎng)址 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,大多數(shù)需要使用的類都有,javax.xml.crypto不再其中,使得我要部署一個SAML2的實現(xiàn)時玩不
轉(zhuǎn)。
2、Google
AppEngine提供了一個DataStore,使用JDO訪問數(shù)據(jù),其查詢語言支持GQL?;竟δ苁蔷邆涞?,但是也是存在很大的局限性,最多返回
1000行數(shù)據(jù),COUNT(*)也是最多返回1000行。這個限制使得很多應(yīng)用要跑在其上,會很麻煩。
3、部署很簡單,在Eclipse中使用Google提供的插件,輸入帳號密碼就可以部署了,太簡單了。但我使用的過程中,經(jīng)常出現(xiàn)某些時段無法部署的情況,通常遇到這種情況,多嘗試幾次或者過段時間再嘗試就好了。
4、管理界面簡潔方便,功能基本完備。包括性能監(jiān)控、數(shù)據(jù)管理、日志、計費等都有。
總結(jié)
Google的AppEngine Java版本已經(jīng)具備了基本功能,可以部署簡單應(yīng)用了,但是由于其功能不夠完備,目前大多數(shù)應(yīng)用要部署在其上,都會要做相當(dāng)大的修改或者無法實現(xiàn)。
我在Google AppEngine上部署了一個Java應(yīng)用(OpenID測試)
http://cogito-study.appspot.com
Google Apps不支持線程,所用到的庫openid4java需要創(chuàng)建線程(因為HttpClient),我修改了openid4java的實現(xiàn),使得其支持Google App Engine。
部署在Google App Engine上的應(yīng)用可以應(yīng)用任何OpenID Provider登陸,包括Google、Yahoo、MSN等。
你可以通過這個測試網(wǎng)站了解OpenID
最近花了較多時間學(xué)習(xí)單點登陸以及相關(guān)的安全技術(shù),做一個簡單的總結(jié),發(fā)表我的一些看法。拋磚引玉,希望各位朋友參與討論。
單點登陸,鳥語原文為Single Sign-On,縮寫為SSO。別以為單點登陸是很時髦高深的技術(shù),相反單點登陸是很古老的技術(shù),例如1980年kerberos v4發(fā)布,一直發(fā)展至今,被Windows、Mac OS X、Linux等流行的操作系統(tǒng)所采用,是為應(yīng)用最廣泛的單點登陸技術(shù)。
kerberos適用于局域網(wǎng),十分成熟?;ヂ?lián)網(wǎng)發(fā)展之后,多個網(wǎng)站需要統(tǒng)一認(rèn)證,業(yè)界需要適合互聯(lián)網(wǎng)的單點登陸技術(shù),也就是WEB SSO。2002年,微軟提出了passport服務(wù),由微軟統(tǒng)一提供帳號和認(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é)院派的腐尸味道,縮寫十分怪異,令人望而生畏。計算機行業(yè),向來崇尚時髦,SAML這一名稱使得其較少受到大眾程序員的關(guān)注。
SAML的標(biāo)準(zhǔn)制定者,來自SUN、BEA、IBM、RSA、AOL、Boeing等大公司,制定技術(shù)規(guī)范相當(dāng)專業(yè)有水準(zhǔn),系統(tǒng)分層合理,抽象了幾個概念把整個系統(tǒng)描述得很清楚,使用流行技術(shù)XML Schema來描述協(xié)議,使用到了XML-Sign和XML Encrypt等較為前緣XML安全技術(shù)。
SAML的基本部分包括Protocol、Bingding、Profile、Metadata、AuthenticationContext。其中Protocol是交互消息的格式,例如AuthnRuequest/Response(認(rèn)證請求/響應(yīng))的消息對。Bingding是指協(xié)議所采用的傳輸方式,例如使用HTTP Redirect或HTTP POST或SOAP的方式傳輸Protocol中所定義的消息。Profile是系統(tǒng)角色間交互消息的各種場景,例如Web Single Sign-ON是一種Profile、Single Sign-Out也是一種Profile、身份聯(lián)邦也是一種Profile。各個參與方所提供的服務(wù)的描述信息為metadata。系統(tǒng)的認(rèn)證方法通常是千差萬別的,AuthenticationContext是SAML中定義的認(rèn)證擴展點,可以是最普通的User Password認(rèn)證,也可以是kerberos認(rèn)證,也可以是電信常用的RADIUS,或者是動態(tài)密碼卡。
SAML在Java企業(yè)應(yīng)用中,得到廣泛支持,IBM、BEA、ORACLE、SUN的Java應(yīng)用服務(wù)器都提供了SAML的支持,曾經(jīng)有人說,SAML就是如同JDBC一樣,將會是使系統(tǒng)集成的準(zhǔn)入證。SAML有很多開源實現(xiàn),包括SUN公司的Open SSO,不幸的是,這些開源實現(xiàn)都不夠好,或者相當(dāng)糟糕,如果我們需要支持SAML協(xié)議,可能需要在開源的版本上裁剪或者另行開發(fā)。
SAML考慮了Web SSO,也考慮了傳統(tǒng)的SSO集成,包括Kerberos和LDAP的集成,其中Attributed擴展機制以及相關(guān)規(guī)范,使得SAML擁有良好的擴展性,很好集成傳統(tǒng)協(xié)議和支持新協(xié)議。
SAML是一個定義良好的規(guī)范,概念清晰,分層合理,擴展性良好,一切都很棒,但是有一點不好,就是曲高和寡!
-------------
OpenID
有一些互聯(lián)網(wǎng)公司,擁有眾多很多帳號,很牛B,例如GOOGLE、YAHOO、Facebook,希望別人的系統(tǒng)使用它們的帳號登陸。他們希望一種足夠簡單的WEB SSO規(guī)范,于是選擇一種草根網(wǎng)絡(luò)協(xié)議OpenID。OpenID,名字取得好,顧名思義,一看就知道它是干嘛的。國內(nèi)也有它的Fans,例如豆瓣網(wǎng)。openID的確足夠簡單,但是協(xié)議本身是不完善,可能需要一些補充協(xié)議才能夠滿足業(yè)務(wù)需求。例如GOOGLE采用OpenID + OAuth。目前支持OpenID有Yahoo、Google、Windows Live,還有號稱要支持OpenID的Facebook。目前Yahoo和Google宣稱對OpenID的支持,但是其實是有限制的,Yahoo的OpenID只有少數(shù)合作伙伴才能獲得其屬性,Google也只有在其Google Apps中才能獲得賬號的Attribute。用戶賬號畢竟是一個互聯(lián)網(wǎng)公司的最寶貴資源,希望他們完全分享賬號是不可能的。
Open ID和SAML兩種規(guī)范,都將會減少系統(tǒng)間交互的成本,我們提供Open API時,應(yīng)該支持其中一種或者或兩種規(guī)范。
--------------
OAuth
oAuth涉及到3大塊的交互和通信。1. 用戶,2. 擁有用戶資料/資源的服務(wù)器A,3. 求資源的服務(wù)器B,。
oAuth的典型應(yīng)用場景(senario)
以前,用戶在 擁有資源 的的網(wǎng)站A有一大堆東西;現(xiàn)在用戶發(fā)現(xiàn)了一個新的網(wǎng)站B,比較好玩,但是這個新的網(wǎng)站B想調(diào)用 擁有資源的網(wǎng)站A的數(shù)據(jù)。
用戶在 求資源的網(wǎng)站B 上,點擊一個URL,跳轉(zhuǎn)到 擁有 資源的網(wǎng)站A。
擁有資源的網(wǎng)站A提示:你需要把資源分享給B網(wǎng)站嗎?Yes/No。
用戶點擊 Yes,擁有資源的網(wǎng)站A 給 求資源的網(wǎng)站B 臨時/永久 開一個通道,然后 求資源的網(wǎng)站 就可以來 擁有資源的網(wǎng)站 抓取所需的信息了。
(參考資料:http://initiative.yo2.cn/archives/633801)
(摘抄)
--------------
內(nèi)部系統(tǒng)間集成使用LDAP、Kerberos,外部系統(tǒng)集成使用SAML或者OpenID + OAuth,這是一種建議的模式。
------------
PAM
人們尋找一種方案:一方面,將鑒別功能從應(yīng)用中獨立出來,單獨進行模塊化設(shè)計,實現(xiàn)和維護;另一方面,為這些鑒別模塊建立標(biāo)準(zhǔn) API,以便各應(yīng)用程序能方便的使用它們提供的各種功能;同時,鑒別機制對其上層用戶(包括應(yīng)用程序和最終用戶)是透明的。直到 1995 年,SUN 的研究人員提出了一種滿足以上需求的方案--插件式鑒別模塊(PAM)機制并首次在其操作系統(tǒng) Solaris 2.3 上部分實現(xiàn)。插件式鑒別模塊(PAM)機制采用模塊化設(shè)計和插件功能,使得我們可以輕易地在應(yīng)用程序中插入新的鑒別模塊或替換原先的組件,而不必對應(yīng)用程序做任何修改,從而使軟件的定制、維持和升級更加輕松--因為鑒別機制與應(yīng)用程序之間相對獨立。應(yīng)用程序可以通過 PAM API 方便的使用 PAM 提供的各種鑒別功能,而不必了解太多的底層細節(jié)。此外,PAM的易用性也較強,主要表現(xiàn)在它對上層屏蔽了鑒別的具體細節(jié),所以用戶不必被迫學(xué)習(xí)各種各樣的鑒別方式,也不必記住多個口令;又由于它實現(xiàn)了多鑒別機制的集成問題,所以單個程序可以輕易集成多種鑒別機制如 Kerberos 鑒別機制和 Diffie - Hellman 鑒別機制等,但用戶仍可以用同一個口令登錄而感覺不到采取了各種不同鑒別方法。PAM 后來被標(biāo)準(zhǔn)化為 X/Open UNIX® 標(biāo)準(zhǔn)化流程(在 X/Open 單點登錄服務(wù)(XSSO)架構(gòu)中)的一部分。(摘抄)
如果我們設(shè)計一個認(rèn)證系統(tǒng),PAM是應(yīng)該參考借鑒的。
-------------
JAAS
Java Authentication Authorization Service(JAAS,Java驗證和授權(quán)API)提供了靈活和可伸縮的機制來保證客戶端或服務(wù)器端的Java程序。Java早期的安全框架強調(diào)的是通過驗證代碼的來源和作者,保護用戶避免受到下載下來的代碼的攻擊。JAAS強調(diào)的是通過驗證誰在運行代碼以及他/她的權(quán)限來保護系統(tǒng)面受用戶的攻擊。它讓你能夠?qū)⒁恍?biāo)準(zhǔn)的安全機制,例如Solaris NIS(網(wǎng)絡(luò)信息服務(wù))、Windows NT、LDAP(輕量目錄存取協(xié)議),Kerberos等通過一種通用的,可配置的方式集成到系統(tǒng)中。在客戶端使用JAAS很簡單。在服務(wù)器端使用JAAS時情況要復(fù)雜一些。(摘抄)
-------------
Spring Security,Spring框架大名鼎鼎,Spring Security屬于SpringFramework旗下的一個子項目,源自acegi 1.x發(fā)展起來。很多人項目應(yīng)用了spring security,但我個人看來,spring security絕對不算是一個設(shè)計良好的安全框架。其設(shè)計感覺就是一個小項目的安全認(rèn)證實踐罷了。
-------------
CAS
應(yīng)用最廣的開源單點登陸實現(xiàn)了,其實現(xiàn)模仿Kerberos的一些概念,例如KDC、TGS等等,都是來自于Kerberos。CAS對SAML和OpenID協(xié)議支持得不夠好。個人感覺類似Kerberos的機制在互聯(lián)網(wǎng)中可能過于復(fù)雜了。我感覺單純的ticket機制,過于局限于基于加密解密的安全了,感覺上SAML的Assertion概念更好,Assertion可以包括認(rèn)證、授權(quán)以及屬性信息。
-------------
--------------------------
09博客園紀(jì)念T恤
新聞:
Wordpress發(fā)布實時RSS技術(shù) 推動實時網(wǎng)絡(luò)發(fā)展
網(wǎng)站導(dǎo)航:
博客園首頁 個人主頁 新聞 社區(qū) 博問 閃存 找找看
現(xiàn)在很多開源項目在使用LOG的時候做了不好的示范--在基類中實例化的方式使用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)類被繼承的時候,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è)計(修訂版)
新聞:
2008年最精彩科技圖片:電流運動模擬圖居首
導(dǎo)航:
博客園首頁 知識庫 新聞 招聘 社區(qū) 小組 博問 網(wǎng)摘 找找看
文章來源:
http://www.cnblogs.com/jobs/archive/2009/01/05/1368894.html
Eclipse包含很多插件,插件之間有復(fù)雜的依賴關(guān)系,如果使用單獨下載安裝的方式,容易遺失部分需要依賴的插件。
在Ecliipse的Software Update功能中安裝插件,能夠解決插件依賴的問題,但是在Eclipse 3.4之前的版本,Software Update不能夠多線程同時下載,遇到網(wǎng)速較慢的更新站點時,需要漫長的等待,有時候安裝一個插件,需要數(shù)個小時,甚至更久。
在Eclipse 3.4之后,Software Update有了很大的改變,可以多線程下載了,但是不能手工選擇鏡像,它會笨笨的選擇一些很慢的站點,效果變得更差了,下載速度時快時慢,但是經(jīng)常都比以前手工選擇鏡像要慢。經(jīng)常選擇一些只有數(shù)百B速度的下載站點,令人抓狂!
所以說,Eclipse 3.4的Software Update功能依然令失望。
期待數(shù)年,終于盼來了新版的Software Update功能,但是新版的更差了,哎。。。
摘要: 我們在開發(fā)中,經(jīng)常需要遍歷一個目錄下的所有文件,常用的辦法就是使用一個函數(shù)遞歸遍歷是常用的辦法。但是遞歸函數(shù)的缺點就是擴展不方便,當(dāng)然你對這個函數(shù)加入一個參數(shù)FileHandler,這樣擴展性稍好一些,但是仍然不夠好,比如說,不能根據(jù)遍歷的需要中途停止遍歷,加入Filter等等。我實現(xiàn)了一個FileIterator,使得遍歷一個目錄下的文件如何遍歷一個集合中的元素一般操作。
閱讀全文
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ā)、高性能方面又進一步,JSR 203應(yīng)該會在JDK 7中實現(xiàn),屆時隨著JDK 7的發(fā)布,將會有更多的基礎(chǔ)軟件使用Java實現(xiàn),而且有極好的性能。
在磁盤I/O和網(wǎng)絡(luò)大規(guī)模并發(fā)I/O方面都會得到更好的性能。
可以預(yù)見受益的程序:
1、WEB服務(wù)器 Tomcat、Jetty等,在Windows下,Java將可以使用IOCP,而不是現(xiàn)在nio所用的select,網(wǎng)絡(luò)并發(fā)性能將會得到大幅度提升。在Linux下則應(yīng)該改變不多,畢竟linux現(xiàn)在并發(fā)最好性能的網(wǎng)絡(luò)I/O EPOLL,JDK 6.0 nio的缺省實現(xiàn)就是epoll。
2、數(shù)據(jù)庫應(yīng)用程序。如Derby、Berkeley DB Java Edition等使用Java實現(xiàn)的數(shù)據(jù)庫,性能將會得到更好的提升,有望能夠誕生和Oracle、SQL Server一樣強大的100% Pure Java的數(shù)據(jù)庫系統(tǒng)。
3、其他網(wǎng)絡(luò)應(yīng)用程序。例如DNS、LDAP等,隨著MINA之類的框架更強大和JDK的原生支持,將會越來越多的服務(wù)器程序使用Java實現(xiàn)。
在新項目中,除了一些框架所依賴的配置文件使用XML外,基本沒有使用XML。JSON基本替代了原來XML在程序內(nèi)的位置。在以前,我們不愿意使用一種私有的格式,于是選擇了XML。選擇XML的理由,可能是大家都用它,所以我們也用它。
XML 是一種很好的技術(shù),但是目前的情況來看,XML被濫用了,SOAP是XML被濫用的一種典型,程序內(nèi)部的表示使用XML也是濫用的一種典型??吹降囊环N情況,一個對象toString使用XML格式輸出,導(dǎo)致日志文件十分羅嗦,調(diào)試時,在watch窗口中看到一大堆<tag>。
在新項目中,認(rèn)真考慮這種情況,找到了另外一種選擇,那就是JSON。選擇JSON的理由很充分:
1、JSON的解釋性能要比XML要好,要簡潔緊湊。
2、可讀性要比XML好。JSON本身就是JavaScript的語法,和程序員的思維,而非文檔編寫的思維。
3、JavaScript原生支持,客戶端瀏覽器不需要為此使用額外的解釋器,在web環(huán)境中使用特別合適。
在java中使用json,目前需要注意一些情況:
1、目前開源的JSON-LIB代碼質(zhì)量不好,最好是在此基礎(chǔ)之上修改一個版本,或者自己重新開發(fā)一個版本。
2、使用new Date的方式替代JSON-LIB中的{year:2007, month:12, ....}之類的方式
3、JSON-LIB中,object的propertyName在輸出的時候,都帶上"",例如{"name": "溫少"}, 其中name是的雙引號是不必要的,在輸出時應(yīng)該判斷,不需要的就是就不加上"",減少網(wǎng)絡(luò)流量。
4、JSON的解釋器中,應(yīng)該支持簡單的表達式,例如new Date()、new Date(2939234723)之類的,這使得JSON的表達能力會更強一些。
5、JSON應(yīng)該分兩種,一種只支持簡單格式,類似開源的JSON-LIB,一種是通過JavaScript解釋器來實現(xiàn)的。后者在程序中傳輸數(shù)據(jù)時,能夠得到更強大的表達能力,但是也會導(dǎo)致安全問題,需要慎重使用。
1、
XP中的結(jié)對編程。XP編程中,有一些思想總結(jié)的很好,例如測試驅(qū)動,但又有極度的荒唐的就是結(jié)對編程。結(jié)對編程是我看到過的最荒唐最可笑的軟件工程方
法,兩倍的投入,一半的產(chǎn)出,可謂事倍功半。以前看結(jié)對編程只是覺得荒唐可笑,后來看了李安的電影《斷背山》,覺得以“斷背”來形容結(jié)對編程最適合了,結(jié)
對編程簡直就是專門為“男同志”們度身定做的軟件工程方法,你想一對“男同志”,每天手牽手背靠背進行“結(jié)對編程”,是多么“浪漫有趣”的事情。不過這只
對“男同志”們的浪漫有趣,對工作本身一點也不有趣!
--------------
2、JDO投票鬧劇(2004-2005)。
一個通過黑客式靜態(tài)AOP方式旁門左道實現(xiàn)的持久化技術(shù)JDO,竟然會被一些人追捧,這本身就是一個很荒唐的事情了。在JCP的投票中,JDO被否決了,
這一點也不奇怪,奇怪的是投票結(jié)果出來之后的鬧劇。一些人以“政治陰謀論”來說事,說JDO不被通過,是因為政治原因,而非技術(shù)原因,這個荒唐的理由竟然
被社區(qū)的很多人相信了,一片聲討,JCP迫于壓力,重新投票,通過了JDO相關(guān)的JSR。但是JDO并沒有因此有一點點起色,一直沉淪至今。JDO通過靜
態(tài)AOP(enhance)的方式使得代碼無法調(diào)試,就單這一點,就足以使JDO永遠無法流行。
這件事情很明確表明兩點:1)、不要相信一些技術(shù)作家的判斷力;2)、普通的大眾沒有判斷能力,會人云亦云。
當(dāng)年荒唐的文章選錄:
《程序員》2005年第2期 http://blog.csdn.net/gigix/archive/2005/01/21/262163.aspx
---------------
竟
然64個annotation,沒有分類,放在同一個package下,同一個package(javax.persistance)還有其他java文
件,共有88個java文件。不看內(nèi)容本身,單從表面,都覺得這是混亂不堪的事情。這是那個豬頭的杰作?glassfish上下載的源碼中,這些java
文件似乎都沒有author,估計也不好意思把名字放出來見人吧!
------
覺得對象關(guān)系存儲方面一直沒有突破,也沒有好的產(chǎn)品出來,其中一個原因,就是從沒有過優(yōu)秀的工程師投身過這個領(lǐng)域。關(guān)系數(shù)據(jù)庫為什么能夠一直堅守領(lǐng)地,成為絕大多數(shù)商業(yè)應(yīng)用的基石,其中一個原因就是有過大量的精英投身于此,包括兩個圖靈獎獲得者。
關(guān)
系數(shù)據(jù)庫,為了描述關(guān)系,創(chuàng)造一門SQL語言,將關(guān)系一些操作,例如投影(select)、選擇(where)、分組(group
by)等等,抽象得形象易懂,功能強大。對于數(shù)據(jù)的操作,SQL語言是最強大,也是最方便的,也是最易于使用的。一些非程序員的IT從業(yè)人員,非計算機專
業(yè)的人員都能夠熟練掌握SQL。
OO和Relational都是偉大的技術(shù),從計算機最高榮譽獎可以看出這兩個技術(shù)的偉大。OO的圖靈獎獲得者是三個,Relational的圖靈獎獲得者是兩個。
面向?qū)ο蠹夹g(shù)自1967年simula引進以來,所想披靡,93年-98年從C++開始流行,然后到Java,成為主流編程技術(shù)。Relational沒有OO那么輝煌,但是在數(shù)據(jù)存儲方面的地位固如磐石,長期占據(jù)絕對的地位。
曾
經(jīng)OO技術(shù)涉足于數(shù)據(jù)存儲領(lǐng)域,但終究沒有成功。面向?qū)ο髷?shù)據(jù)庫的變現(xiàn)總是差強人意,面向?qū)ο蟮姆绞讲僮鲾?shù)據(jù),總是不如使用關(guān)系那么方便,那么靈活,那么
易于使用,那么好的性能。于是人們在數(shù)據(jù)存儲和處理方面,不在青睞面向?qū)ο蠹夹g(shù),而是仍然使用關(guān)系方式,使用SQL語言,使用關(guān)系運算操作數(shù)據(jù)。面向?qū)ο?
數(shù)據(jù)庫成了曇花一現(xiàn)的東西,并且可能永遠都不會再流行了。
OO成了主流編程技術(shù),Relational占據(jù)了絕對的數(shù)據(jù)存儲地位,這兩大技術(shù)需要交互,需要橋接,這需要OR-Mapping。Relational雖然好,但我們也要與時俱進,所以也需要OR-Mapping。
但
是,做OR-Mapping時,不積極吸取relational方式對數(shù)據(jù)處理的靈活性、方便性、簡單性,而只強調(diào)Relational和對象之間的的
Mapping,試圖以面向?qū)ο蟮姆绞讲僮鲾?shù)據(jù),這是錯誤的方向。以前的EJB、現(xiàn)在Hibernate、JPA都犯了同樣的錯誤,試圖以更面向?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ù),亦屬于本末倒置。需求人員都會用的SQL語言,對數(shù)據(jù)操作最方便最簡單最強大的SQL語言,竟然成了令人生畏的紙老虎,可笑啊。
-------------
以下是過去的一些業(yè)界浮躁不理智:
1、面向?qū)ο髷?shù)據(jù)庫。曾被熱衷而吹捧,面向?qū)ο髷?shù)據(jù)庫的變現(xiàn)總是差強人意,面向?qū)ο蟮姆绞讲僮鲾?shù)據(jù),總是不如使用關(guān)系那么方便,那么靈活,那么易于使用,那么好的性能。于是人們在數(shù)據(jù)存儲和處
理方面,不在青睞面向?qū)ο蠹夹g(shù),而是仍然使用關(guān)系方式,使用SQL語言,使用關(guān)系運算操作數(shù)據(jù)。面向?qū)ο髷?shù)據(jù)庫成了曇花一現(xiàn)的東西,并且可能永遠都不會再
流行了。
2、
JDO投票鬧劇。2004-2005年,JDO的JSR在JCP投票被否決的,無聊者在Java社區(qū)以及媒體發(fā)起鬧事,陰謀論其為政治謀殺,幾大公司是的
迫于形象,重新投票使得JDO被通過,但JDO這種靜態(tài)AOP叫雕蟲小計式技術(shù),不單開發(fā)過程不方便,而且會使得"enhance"之后的代碼不可調(diào)試。
這完全是對開發(fā)者不友好的技術(shù),沒有前途的技術(shù),竟然會有人為它在JCP投票不通過鳴不平。這件事情使得我更堅信一點,不要相信那些技術(shù)編輯的判斷力。
3、
AOP。也是最近這幾年流行的一個名詞了。起了一個和OOP相似的名字,但是和偉大的OOP相比,它完全不算是什么。AOP只是一種很小很小的技巧而已,
靜態(tài)的AOP是黑客式的插入代碼,會導(dǎo)致代碼不可調(diào)試,動態(tài)的AOP能力有限,AOP最常被引用例子“日志AOP”是不合適,有用的日志通常是精心設(shè)計
的,AOP方式的日志在生產(chǎn)環(huán)境中基本上是不可用。OO這么多年,這么為偉大,人們總是希望自己能做點什么和偉大的OO相比,于是命名為AOP,這是一個
可笑的名字,前些年還有人談?wù)撁嫦驅(qū)ο蟮奈磥硎敲嫦蚴聦崳彩峭瑯拥目尚?。AOP有價值,但它是一種小技巧,和名字不般配。
--------------
目前在流行,但是可能是不理智的技術(shù):
1、hibernate之類的ORM,試圖以面向?qū)ο蠓绞讲僮鲾?shù)據(jù),和面向?qū)ο髷?shù)據(jù)庫一樣,重蹈覆轍。
2、Ruby,一個小腳本語言,只是因為動態(tài)類型、mixin之類的功能,還沒有被證明有生產(chǎn)力,有效益可用的腳本語言,就被媒體吹到天上去。Ruby有價值,但是最終結(jié)果會離大家的期待相差甚遠。
中國最大的在線記賬及商務(wù)管理平臺—金蝶“友商網(wǎng)”(www.youshang.com)正式上線!請立刻體驗!
摘要: 本文描述一種ID生成算法
閱讀全文
摘要: 本文介紹流行的非阻塞算法關(guān)鍵思想Compare And Set在數(shù)據(jù)庫開發(fā)中的應(yīng)用
閱讀全文
由于在實際工作中使用到了mina,所以一直關(guān)注其mail-list。
最近mina的mail-list討論的一個問題,就是提供的manual close connector,這個問題可害慘我了。
原來的Connector,無論是SocketConnector或者VmPipeConnector,都是沒有提供close方法的,而且不會自動釋放。
原來做得一個網(wǎng)絡(luò)程序客戶端,每次重新創(chuàng)建的時候,都會new SocketConnector,可是,SocketConnector不會被GC回收的,所使用的線程和內(nèi)存都不會自動釋放,這個程序在服務(wù)器斷開時會重連,于是,當(dāng)服務(wù)器重啟或者網(wǎng)絡(luò)中斷時,內(nèi)存泄漏就產(chǎn)生了,程序慢慢的占用更多的內(nèi)存,直至崩潰!
解決此問題的辦法就是,要么使用Singleton,要么使用即將發(fā)布的1.1.3!
使用maven2一段時間了,我基本把我自己能夠遷移的project都轉(zhuǎn)換為maven2 project,以下是我的一點感想。
(原作者溫少,轉(zhuǎn)載請注明)
亂世盼英雄
現(xiàn)在的軟件開發(fā),比過去的軟件開發(fā)要復(fù)雜得多。包括在參與開發(fā)的人數(shù)、代碼規(guī)模、復(fù)雜的需求、依賴包的復(fù)雜性、使用到更多的技術(shù)、多個項目之間的復(fù)雜依賴關(guān)系。
現(xiàn)在的開發(fā)人員,要掌握的技術(shù)要比過去的開發(fā)人員要多,不是現(xiàn)在的開發(fā)人員比以前的開發(fā)人員本身更優(yōu)秀,而是擁有更多的資料、更多的學(xué)習(xí)機會、更多更大規(guī)模的時間,同時軟件行業(yè)也在發(fā)展。說一句題外話,老程序員,如果不與時俱進,靠老本,是無法和新一代程序員競爭的,當(dāng)然,老程序員,擁有更多的經(jīng)驗,掌握新技術(shù)的速度更快,這又是另外一回事。
開發(fā)人員掌握的技術(shù)更復(fù)雜了,項目用得的技術(shù)自然也是更復(fù)雜,例如一個web項目,可能使用到很多技術(shù),面向?qū)ο?、泛型、or-mapping、依賴注入(spring-framework)、全文檢索(lucene)、數(shù)據(jù)庫、集群、工作流、web service等等。
由于使用了多種技術(shù),這些技術(shù)可能是JDK提供的,也可能是第三方開源組織提供的,或者不同的商業(yè)公司提供的。
于是出現(xiàn)了一個新的難題,就是包依賴復(fù)雜性。以前,你很難想象你的代碼依賴數(shù)十個不同開源組織、商業(yè)公司提供的庫。例如,我們經(jīng)常使用的log4j、junit、easymock、ibatis、springframework,每個組件都有悠久的歷史,存在不同的版本,他們之間版本還有依賴關(guān)系。
項目依賴的復(fù)雜性,經(jīng)常的,一個較大部門有10-30個項目是常事,項目之間有不同版本的依賴關(guān)系,部門與部門之間的項目也存在復(fù)雜的版本依賴關(guān)系。
Eclipse本身提供Project的依賴,但是簡單的依賴顯然解決不了問題。例如Project B依賴Project A,Project A依賴第三方的jar包abc-1.0.jar,那么需要在兩個項目的lib下都存放abc-1.0.jar,這產(chǎn)生冗余,當(dāng)Project數(shù)量多起來,這個冗余就產(chǎn)生了管理問題,如果需要將abc-1.0.jar升級為abc-1.1.jar,則需要在兩個Project中同時修改,如果Project數(shù)量達到10個以上,而且是不同項目組維護的項目,這個就是非常麻煩的事情。而且Project A修改依賴,為啥需要Project B也作相應(yīng)的修改呢?
需要解決此問題,就需要在Project A的包中描述其依賴庫的信息,例如在META-INFO記錄所以來的abc-1.0.jar等。Eclipse的plug-in擁有類似的方案,但是這樣一來,就使得開發(fā)Project B的項目組,需要把Project A的代碼從源代碼庫中check out出來。在依賴鏈末端的項目組是很慘的。
由于Project數(shù)量眾多,關(guān)系復(fù)雜,dailybuild的ant腳本編寫成了很麻煩的事情,使用Project依賴的方式,更加使得編寫dailybuild ant script是非常痛苦的事情。
當(dāng)然也可以不使用project依賴的方式,而使用artifact lib的依賴方式,但是artifact lib的依賴方式,就是同時修改多個project,互相調(diào)試時帶來了痛苦。
在以前,我們面臨這些問題時,唯一的感覺就是,這事情TMD的太麻煩,幾乎是失控了。
maven的出現(xiàn),解決這種問題看到了希望。maven出現(xiàn)的原因就是,現(xiàn)在的開發(fā)管理復(fù)雜度達到了一定程序,需要專門的開發(fā)管理工具,這樣的工具需要涵蓋開發(fā)的各個階段,包括工程建立、配置依賴管理、編譯、測試、產(chǎn)生分析報告、部署、產(chǎn)生制品等階段。目前,各個階段的工具都存在,但是不是集成的,對使用帶來了很大麻煩。maven集成了這些工具,提高了統(tǒng)一的環(huán)境,使得使用更簡單。
現(xiàn)在maven非常流行了,apache上所有java project都已經(jīng)build by maven,其他跟進的開源項目非常多,例如mule、hibernat等等,商業(yè)公司也很多在采用,sun公司提供有maven2 repository。
現(xiàn)在,2007年,如果你還沒采用maven project,你可能需要思考一下,是否你使用了不恰當(dāng)?shù)姆绞焦芾淼拇a,或者你落伍了?
maven的一些常用任務(wù)
compile 編譯代碼
test 運行單元測試
package 打包代碼
site 產(chǎn)生報告,例如java doc、junit的通過率報告和覆蓋率報告、findbugs的分析報告等等。
assembly 使用需求產(chǎn)生assembly,例如把生成一個程序目錄,包括bin、config、lib、logs,把依賴包放在lib中。
deploy 部署制品到repository中。
這些都是常用的任務(wù),在以前編寫腳本很麻煩,現(xiàn)在在maven中,一切都是很簡單,需要仔細設(shè)置時功能又強大到令人驚嘆,例如site的fml,assembly。
maven資源庫
maven官方提供了一個常用lib的資源庫,包括apache的所有java項目,開源常用的基本都能夠找到,例如mule、c3p0、easymock、hibernate、springframework、json等等,版本齊全,任你挑選。
可以部署本地資源庫代理提高下載速度。使用maven proxy。
maven體系結(jié)構(gòu)
maven使用plug-in的體系,使用很好的自動更新策略,本身用到的jar都是lazy download的,可以指定download的repository。這樣,初始下載的maven是一個很小的程序,使用的時候從本地的資源庫或者本地代理資源庫高速下載lib。maven的插件體系,充分利用了internet的資源豐富和局域網(wǎng)的高速帶寬,使用本地repository時,可以享受到每秒鐘數(shù)M的下載速度,感覺就是,人生真是美妙!
elcipse的plug-in體系,就不是那么好用了,我們使用eclipse的find and install功能下載或者更新插件時,慢如蝸牛,依賴缺失時的煩惱,更新一個plug-in,可能耗費你數(shù)個小時,第三方的plug-in的下載服務(wù)器可能更慢,例如subversive的plugin-in,有一次我花了兩天還沒下載好,只好使用下載工具下載好,copy到plug-in目錄下。此時,我們總是感嘆,人生總是有很多煩惱事??!
相比之下,高下立判!在此我不是說eclipse的plug-in體系結(jié)構(gòu)設(shè)計不好,eclipse的插件體系非常優(yōu)秀,但是還有很大改進空間!
在beep4j上作了一些修改,并且在此之上實現(xiàn)了一個基于BEEP協(xié)議的服務(wù)器框架。
BEEP協(xié)議提供了Session、Channel、Greeting、Profile、Frame等概念,這些基礎(chǔ)概念之上,很容易進行更高級的應(yīng)用層協(xié)議設(shè)計。
BEEP協(xié)議的特征和能力
長連接
對等通訊
請求\應(yīng)答式交互
在一個Session中創(chuàng)建多個獨立的傳輸通道(Channel)
在一個通道中進行多個異步請求(滑動窗口)
可以使用不同的消息編碼方式,包括二進制、文本、XML等,類似SMTP的MIME,使得可以在高效的二進制、易懂的文本之間作出選擇。
這是一個在傳輸層和應(yīng)用層之間的協(xié)議,應(yīng)用場景很廣泛,RFC標(biāo)準(zhǔn)化,官方網(wǎng)站為http://www.beepcore.org/。很多公司都有相應(yīng)的支持,包括IBM。在不同語言下都是相應(yīng)的實現(xiàn),包括C、Java、Python、Ruby、JavaScript Beep client等等。
關(guān)于ContentType和Codec
在Java程序之間通訊,前期可能不希望作更多的協(xié)議編碼、解碼工作,使用spring bean xml格式傳輸是一種方式。
在一些對效率不是特別高,又不喜歡使用機器友好的XML的場景,可以使用JSON的編碼方式。
在一些對效率要求很高的場景,ASN.1或者自定義的二進制編碼格式。
甚至使用土土的序列化編碼方式
匆忙寫成,以后會慢慢補充
請用力一擊中等規(guī)模的并發(fā)程序設(shè)計
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月刊《程序員》,專題為“多核時下的軟件開發(fā)”?!冻绦騿T》并非陽春白雪,它面向大眾程序員。面向大眾的《程序員》介紹多核、并發(fā),也意味著并發(fā)程序設(shè)計的開始進入中國大眾程序員的視野。
并發(fā)程序設(shè)計,在很多的書籍或者文章中,都會提到他的一個特點,復(fù)雜。這個特性,也導(dǎo)致了在以往并發(fā)程序設(shè)計只為高級程序員所專用。
復(fù)雜度并非事物的固有屬性,并發(fā)程序設(shè)計的復(fù)雜,是我們主觀認(rèn)為。我們認(rèn)為并發(fā)程序設(shè)計復(fù)雜,是因為我們還沒有掌握一些使其簡單化、清晰化的方法。當(dāng)我們掌握相關(guān)方法,研究徹底,并發(fā)就會變得簡單。這個過程已經(jīng)開始了。
以
往,我們需要直接使用一些低級并發(fā)概念來構(gòu)造系統(tǒng),不斷發(fā)明輪子,容易出錯,難以調(diào)試,這種的并發(fā)程序設(shè)計當(dāng)然復(fù)雜,因此也只能為高級程序員所專用。如此
環(huán)境,就如同Dijkstra給我們帶來結(jié)構(gòu)化程序設(shè)計之前的世界一般。很幸運的是,一些軟件業(yè)的先驅(qū)們,已經(jīng)抽象出一些概念,能夠使得并發(fā)程序設(shè)計簡單
化,清晰化。例如Future、Lock-free思想等。
在主流編程語言中,Java走在最前頭,理念領(lǐng)先,提供了實用的庫。在
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ā)程序簡單化。
C++中,Herb Sutter在Visual C++中加入了很多支持并發(fā)的語法特性,包括atomic、future等。boost的線程庫開始引入了第一個高級概念barrier。
Windows
平臺本身提供了功能強大的并發(fā)API,包括WaitForSingle系列,WaitForMulti系列,Auto和Manual模式的Event等
等。.NET平臺基本沒有任何自有的并發(fā)庫和工具類,完全是Windows
API的簡單封裝??梢赃@么說,.NET的類庫沒有為并發(fā)作任何事情,完全吃Windows API的老本。
如同Herb Sutter認(rèn)為,我們很幸運處于并經(jīng)歷這個軟件大變革(并發(fā))。并發(fā)進入主流這個過程將會延續(xù)數(shù)年,Herb Sutter認(rèn)為是2007-2012。
參考我以前寫的一篇文章(Herb Sutter的一些觀點 http://www.cnblogs.com/jobs/archive/2006/11/12/558078.html)
類
似的場景也有,早期面向?qū)ο蠹夹g(shù),也只為少數(shù)高級程序員所掌握,現(xiàn)在剛?cè)腴T的程序員都能說上一大通。數(shù)據(jù)結(jié)構(gòu)算法也是,早期只為少數(shù)優(yōu)秀程序員所掌握,但
現(xiàn)在主流的開發(fā)環(huán)境中就包括了主要的數(shù)據(jù)結(jié)構(gòu)和算法,會用的人一把一把,會用List、Hashtable、快速排序一點也不酷。并發(fā)程序設(shè)計也一樣,將
不再是陽春白雪!
面向?qū)ο蠹夹g(shù)在最初在Simula語言中引進,顧名思義,最初樸素的面向?qū)ο笏枷刖褪悄M,在程序中模擬真實世界。這種
“模擬”,使得程序的組織清晰化,簡單化。但真實世界是充滿著并發(fā)。真實世界的并發(fā)要比虛擬環(huán)境中的并發(fā)要復(fù)雜的多,但是人們輕松應(yīng)付,由此,我們有足夠
的理由相信,并發(fā)程序設(shè)計將不會是一種復(fù)雜難掌握的技術(shù)。
我們談一下實際的場景吧。我們在開發(fā)中,有如下場景
a) 關(guān)閉空閑連接。服務(wù)器中,有很多客戶端的連接,空閑一段時間之后需要關(guān)閉之。
b) 緩存。緩存中的對象,超過了空閑時間,需要從緩存中移出。
c) 任務(wù)超時處理。在網(wǎng)絡(luò)協(xié)議滑動窗口請求應(yīng)答式交互時,處理超時未響應(yīng)的請求。
一種笨笨的辦法就是,使用一個后臺線程,遍歷所有對象,挨個檢查。這種笨笨的辦法簡單好用,但是對象數(shù)量過多時,可能存在性能問題,檢查間隔時間不好設(shè)置,間隔時間過大,影響精確度,多小則存在效率問題。而且做不到按超時的時間順序處理。
這場景,使用DelayQueue最適合了。
DelayQueue
是java.util.concurrent中提供的一個很有意思的類。很巧妙,非常棒!但是java doc和Java SE
5.0的source中都沒有提供Sample。我最初在閱讀ScheduledThreadPoolExecutor源碼時,發(fā)現(xiàn)DelayQueue
的妙用。隨后在實際工作中,應(yīng)用在session超時管理,網(wǎng)絡(luò)應(yīng)答通訊協(xié)議的請求超時處理。
本文將會對DelayQueue做一個介紹,然后列舉應(yīng)用場景。并且提供一個Delayed接口的實現(xiàn)和Sample代碼。
DelayQueue是一個BlockingQueue,其特化的參數(shù)是Delayed。(不了解BlockingQueue的同學(xué),先去了解BlockingQueue再看本文)
Delayed擴展了Comparable接口,比較的基準(zhǔn)為延時的時間值,Delayed接口的實現(xiàn)類getDelay的返回值應(yīng)為固定值(final)。DelayQueue內(nèi)部是使用
PriorityQueue實現(xiàn)的。
DelayQueue = BlockingQueue + PriorityQueue + Delayed
DelayQueue的關(guān)鍵元素BlockingQueue、PriorityQueue、Delayed。可以這么說,DelayQueue是一個使用優(yōu)先隊列(PriorityQueue)實現(xiàn)的BlockingQueue,
優(yōu)先隊列的比較基準(zhǔn)值是時間。他們的基本定義如下
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內(nèi)部的實現(xiàn)使用了一個優(yōu)先隊列。當(dāng)調(diào)用DelayQueue的offer方法時,把Delayed對象加入到優(yōu)先隊列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)先隊列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,是一個緩存的簡單實現(xiàn)。共包括三個類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的實現(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的實現(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) {
// 超時對象處理
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);
}
// 測試入口函數(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);
}
}
}
運行Sample,main函數(shù)執(zhí)行的結(jié)果是輸出兩行,第一行為aaa,第二行為null。
china-pub購書網(wǎng)址:http://www.china-pub.com/computers/common/info.asp?id=34017
1、總體感受
a) 這本書主要介紹的是intel平臺下的多核程序設(shè)計技術(shù),Windows介紹較多,Linux介紹較少,Java更少。作者是Intel公司的平臺架構(gòu)師,我們知道wintel聯(lián)盟,書中的內(nèi)容如此分布也是正常。
b) 此書讓我懂得了很多硬件方面的并行知識。
c)
此書介紹Windows API中和并發(fā)相關(guān)的部分,很詳盡,比Jeffrey
Richter的《Windows核心編成》有深度多了,也精辟多了。顯然《多核程序設(shè)計》作者屬于有經(jīng)驗的工程師,Jeffrey
Richter只是一個寫手,兩者沒有可比性。不過這方面的知識偶早已涉獵,當(dāng)作復(fù)習(xí)一遍罷了。
d) 此書偏向底層,硬件和操作系統(tǒng)層面。更高層面的技術(shù)介紹較少。
e) 第一次了解OpenMP技術(shù)的一些細節(jié)。以前只聽說,也沒查過任何相關(guān)資料,在此書中看到了相關(guān)部分,挺有意思的,感覺那些語法很有趣。Herb Sutter也是要在語法方面動手。反正我在有了一個粗淺認(rèn)識之后,覺得很有意思。
-------------------------
2、并發(fā)流程控制
Fence
在Java
中對應(yīng)的是java.util.concurrent.CountDownLatch。最初接觸CountDownLatch的時候,由于其實現(xiàn)很簡單,
當(dāng)時覺得是一個可有可無的工具類。但后來在不同的場景多次使用,發(fā)現(xiàn)很有用。在此書中再次發(fā)現(xiàn)類似的Fence,用于在共享存儲多處理器或者多核環(huán)境中,
確保存儲操作的一致性。我猜這屬于業(yè)界并發(fā)流控制的典型手段了。
Barrier
在Java中對應(yīng)的是java.util.concurrent.CyclicBarrier。在應(yīng)用程序中,一個場景就是和定時器結(jié)合使用,countDown、await、reset,做定時定量批量處理。
我猜這也屬于業(yè)界并發(fā)流程控制的典型手段了。
(CountDownLatch和CycliBarrier的實現(xiàn)代碼都很簡單,但很有用,他們都屬于并發(fā)流程控制的典型手段)
-------------------------
3、非阻塞算法
InterLocked在Java中對應(yīng)的是java.util.concurrent.atomic.xxx
書中提到了cache行乒乓球現(xiàn)象導(dǎo)致的性能問題,提高了非阻塞算法的復(fù)雜性問題。
關(guān)于性能問題,developerworks上有一片文章,有測試數(shù)據(jù):
《Java 理論與實踐: 流行的原子》 (http://www.ibm.com/developerworks/cn/java/j-jtp11234/index.html)
文章中的測試數(shù)據(jù)表明,直接使用atomic在1個和2個處理器時是最好的,4個處理器以上,使用java.util.concurrent.locks.ReentrantLock性能更好。
java.util.concurrent包,提供了很多高級的概念,隱藏了非阻塞算法帶來的復(fù)雜度,其底層框架達到了最佳性能。
-------------------------
4、任務(wù)分解、數(shù)據(jù)分解以及數(shù)據(jù)流分解
此書中明確提出了這三個概念,很有用,讓我在這方面的知識概念清晰化了。
任務(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中,提供了一種高級的數(shù)據(jù)分解協(xié)同模式j(luò)ava.util.concurrent.Exchanger這個類。早在Java SE
5.0時,Exchanger只支持2Parties,Java SE 6.0支持n
parties。偶想象過一些很酷的應(yīng)用場景,寫過模擬測試,但一直沒有機會用于實際開發(fā)中。
數(shù)據(jù)流分解
書中提到了眾多周知的producer/consumer問題。
其實java.util.concurrent.Exchanger類,既有數(shù)據(jù)分解,又有數(shù)據(jù)流分解,exchanger中的producer和consumer的角色會互換的,很有意思。
-------------------------
5、作為Java程序員的思考
Java SE 5.0之后,提供了util.concurrent包,功能齊全,性能卓越,非常優(yōu)秀。從此書來看,業(yè)界流行的流程控制手段和并發(fā)程序設(shè)計方法一個不落。我們應(yīng)該感謝偉大的Doug Lea,他為我們帶了一個如此完美的并發(fā)庫!
一旦方案想清楚,剩余部分的工作效率瓶頸就在于你的手速了。最近一直看起點中文網(wǎng)上的《師士傳說》,主角葉重一個強項就是手速。
最基本的就是盲打。不會盲打的通常屬于“編碼低能兒”。身邊也有不會盲打的朋友,他們通常都有一個問題,就是眼高手低,說說還行,動手就不行。當(dāng)然他們能夠在IT研發(fā)領(lǐng)域還混得很好,是因為在其他方面擁有優(yōu)秀的能力。
熟練掌握快捷鍵是關(guān)鍵。鍵盤和鼠標(biāo)之間通常有較大的距離,手經(jīng)常在鍵盤和鼠標(biāo)之間移動,會降低效率,也容易導(dǎo)致疲勞,用鼠標(biāo)過多,也容易導(dǎo)致齷齪的鼠標(biāo)手。解決這個問題的辦法,就是純鍵盤操作,其實很多IDE的快捷鍵功能強大,足以讓你純鍵盤操作,高效率編碼。
我比較熟悉的IDE是Eclipse,就以Eclispse來說吧。
Eclipse的keys列表中,屬于Eclipse本身有180多個快捷鍵,要提高編碼速度,就應(yīng)該熟練使用其中絕大多數(shù)。
練習(xí)的辦法:
1、在Windows/Preferences/General/keys中,使用Export,把快捷鍵導(dǎo)出,導(dǎo)出的格式是csv格式,Windows下可以用Excel直接打開,Linux下可以用OpenOffice打開,打開時選擇分隔符為“,”。
2、挨個練習(xí)使用。每天練習(xí)一部分,反復(fù)練習(xí),堅持一段時間。
3、開始的時候,把鼠標(biāo)放到一個不方便使用的角落,盡量不要讓自己用鼠標(biāo)。
4、快捷鍵的組合使用需要加強訓(xùn)練。在不同場景下,認(rèn)真考慮用怎樣的組合快捷鍵最高效。
如此堅持一段時間之后,編碼的過程會很流暢,速度就會大大提高。