java技術(shù)研究

          統(tǒng)計(jì)

          留言簿(3)

          閱讀排行榜

          評論排行榜

          2015年10月16日 #

          tomcat增加error打印

          今天啟動Tomcat啟動不了,報(bào)以下錯: 

          org.apache.catalina.core.StandardContext startInternal 
          SEVERE: Error listenerStart 
          org.apache.catalina.core.StandardContext startInternal 
          SEVERE: Context [/******] startup failed due to previous errors 

          網(wǎng)上找了N多文章,都沒有切中要害。 
          后來在國外網(wǎng)站上搜到一個(gè)方法 
          http://grails.1312388.n4.nabble.com/Deployment-problems-td4628710.html。 
          我試了一下,是可以的。方案如下。 

          Tomcat報(bào)的錯太含糊了,什么錯都沒報(bào)出來,只提示了Error listenerStart。為了調(diào)試,我們要獲得更詳細(xì)的日志。可以在WEB-INF/classes目錄下新建一個(gè)文件叫l(wèi)ogging.properties,內(nèi)容如下 

          Java代碼  收藏代碼
          1. handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler  
          2.   
          3. ############################################################  
          4. # Handler specific properties.  
          5. # Describes specific configuration info for Handlers.  
          6. ############################################################  
          7.   
          8. org.apache.juli.FileHandler.level = FINE  
          9. org.apache.juli.FileHandler.directory = ${catalina.base}/logs  
          10. org.apache.juli.FileHandler.prefix = error-debug.  
          11.   
          12. java.util.logging.ConsoleHandler.level = FINE  
          13. java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter  


          這樣,我們再啟動tomcat時(shí),就會在logs目錄下生成一個(gè)更詳細(xì)的日志error-debug.2012-05-31.log。 

          我們進(jìn)去看看什么錯吧。 
          我碰到的錯誤是FileNotFoundException.大家碰到的錯應(yīng)該各式各樣都有,所以就要具體問題具體分析了。 
          tomcat的logging文檔具體可參考http://tomcat.apache.org/tomcat-7.0-doc/logging.html 

          posted @ 2018-08-14 12:35 小秦 閱讀(586) | 評論 (0)編輯 收藏

          服務(wù)器一般達(dá)到多少qps比較好

          每秒查詢率QPS是對一個(gè)特定的查詢服務(wù)器在規(guī)定時(shí)間內(nèi)所處理流量多少的衡量標(biāo)準(zhǔn),在因特網(wǎng)上,作為域名系統(tǒng)服務(wù)器的機(jī)器的性能經(jīng)常用每秒查詢率來衡量。

          原理:每天80%的訪問集中在20%的時(shí)間里,這20%時(shí)間叫做峰值時(shí)間
          公式:( 總PV數(shù) * 80% ) / ( 每天秒數(shù) * 20% ) = 峰值時(shí)間每秒請求數(shù)(QPS)
          機(jī)器:峰值時(shí)間每秒QPS / 單臺機(jī)器的QPS = 需要的機(jī)器

          問:每天300w PV 的在單臺機(jī)器上,這臺機(jī)器需要多少Q(mào)PS?
          答:( 3000000 * 0.8 ) / (86400 * 0.2 ) = 139 (QPS)

          問:如果一臺機(jī)器的QPS是58,需要幾臺機(jī)器來支持?
          答:139 / 58 = 3

          posted @ 2016-06-08 10:23 小秦 閱讀(725) | 評論 (0)編輯 收藏

          敏捷開發(fā)之Scrum掃盲篇(轉(zhuǎn))

          現(xiàn)在敏捷開發(fā)是越來越火了,人人都在談敏捷,人人都在學(xué)習(xí)Scrum和XP...

           

          為了不落后他人,于是我也開始學(xué)習(xí)Scrum,今天主要是對我最近閱讀的相關(guān)資料,根據(jù)自己的理解,用自己的話來講述Scrum中的各個(gè)環(huán)節(jié),主要目的有兩個(gè),一個(gè)是進(jìn)行知識的總結(jié),另外一個(gè)是覺得網(wǎng)上很多學(xué)習(xí)資料的講述方式讓初學(xué)者不太容易理解;所以我決定寫一篇掃盲性的博文,同時(shí)試著也與園內(nèi)的朋友一起分享交流一下,希望對初學(xué)者有幫助。

           

           什么是敏捷開發(fā)?

          敏捷開發(fā)(Agile Development)是一種以人為核心、迭代、循序漸進(jìn)的開發(fā)方法。

          怎么理解呢?首先,我們要理解它不是一門技術(shù),它是一種開發(fā)方法,也就是一種軟件開發(fā)的流程,它會指導(dǎo)我們用規(guī)定的環(huán)節(jié)去一步一步完成項(xiàng)目的開發(fā);而這種開發(fā)方式的主要驅(qū)動核心是人;它采用的是迭代式開發(fā);

           

          為什么說是以人為核心?

          我們大部分人都學(xué)過瀑布開發(fā)模型,它是以文檔為驅(qū)動的,為什么呢?因?yàn)樵谄俨嫉恼麄€(gè)開發(fā)過程中,要寫大量的文檔,把需求文檔寫出來后,開發(fā)人員都是根據(jù)文檔進(jìn)行開發(fā)的,一切以文檔為依據(jù);而敏捷開發(fā)它只寫有必要的文檔,或盡量少寫文檔,敏捷開發(fā)注重的是人與人之間,面對面的交流,所以它強(qiáng)調(diào)以人為核心。

           

          什么是迭代?

          迭代是指把一個(gè)復(fù)雜且開發(fā)周期很長的開發(fā)任務(wù),分解為很多小周期可完成的任務(wù),這樣的一個(gè)周期就是一次迭代的過程;同時(shí)每一次迭代都可以生產(chǎn)或開發(fā)出一個(gè)可以交付的軟件產(chǎn)品。

           

          關(guān)于Scrum和XP

          前面說了敏捷它是一種指導(dǎo)思想或開發(fā)方式,但是它沒有明確告訴我們到底采用什么樣的流程進(jìn)行開發(fā),而Scrum和XP就是敏捷開發(fā)的具體方式了,你可以采用Scrum方式也可以采用XP方式;Scrum和XP的區(qū)別是,Scrum偏重于過程,XP則偏重于實(shí)踐,但是實(shí)際中,兩者是結(jié)合一起應(yīng)用的,這里我主要講Scrum。

           

          什么是Scrum?

          Scrum的英文意思是橄欖球運(yùn)動的一個(gè)專業(yè)術(shù)語,表示“爭球”的動作;把一個(gè)開發(fā)流程的名字取名為Scrum,我想你一定能想象出你的開發(fā)團(tuán)隊(duì)在開發(fā)一個(gè)項(xiàng)目時(shí),大家像打橄欖球一樣迅速、富有戰(zhàn)斗激情、人人你爭我搶地完成它,你一定會感到非常興奮的。

          而Scrum就是這樣的一個(gè)開發(fā)流程,運(yùn)用該流程,你就能看到你團(tuán)隊(duì)高效的工作。

           

          【Scrum開發(fā)流程中的三大角色】

          產(chǎn)品負(fù)責(zé)人(Product Owner)

          主要負(fù)責(zé)確定產(chǎn)品的功能和達(dá)到要求的標(biāo)準(zhǔn),指定軟件的發(fā)布日期和交付的內(nèi)容,同時(shí)有權(quán)力接受或拒絕開發(fā)團(tuán)隊(duì)的工作成果。

           

          流程管理員(Scrum Master)

          主要負(fù)責(zé)整個(gè)Scrum流程在項(xiàng)目中的順利實(shí)施和進(jìn)行,以及清除擋在客戶和開發(fā)工作之間的溝通障礙,使得客戶可以直接驅(qū)動開發(fā)。

           

          開發(fā)團(tuán)隊(duì)(Scrum Team)

          主要負(fù)責(zé)軟件產(chǎn)品在Scrum規(guī)定流程下進(jìn)行開發(fā)工作,人數(shù)控制在5~10人左右,每個(gè)成員可能負(fù)責(zé)不同的技術(shù)方面,但要求每成員必須要有很強(qiáng)的自我管理能力,同時(shí)具有一定的表達(dá)能力;成員可以采用任何工作方式,只要能達(dá)到Sprint的目標(biāo)。

           

           

          Scrum流程圖

           

          //------------------------

          下面,我們開始講具體實(shí)施流程,但是在講之前,我還要對一個(gè)英文單詞進(jìn)行講解。

          什么是Sprint?

          Sprint是短距離賽跑的意思,這里面指的是一次迭代,而一次迭代的周期是1個(gè)月時(shí)間(即4個(gè)星期),也就是我們要把一次迭代的開發(fā)內(nèi)容以最快的速度完成它,這個(gè)過程我們稱它為Sprint。

           

          如何進(jìn)行Scrum開發(fā)?

          1、我們首先需要確定一個(gè)Product Backlog(按優(yōu)先順序排列的一個(gè)產(chǎn)品需求列表),這個(gè)是由Product Owner 負(fù)責(zé)的;

          2、Scrum Team根據(jù)Product Backlog列表,做工作量的預(yù)估和安排;

          3、有了Product Backlog列表,我們需要通過 Sprint Planning Meeting(Sprint計(jì)劃會議) 來從中挑選出一個(gè)Story作為本次迭代完成的目標(biāo),這個(gè)目標(biāo)的時(shí)間周期是1~4個(gè)星期,然后把這個(gè)Story進(jìn)行細(xì)化,形成一個(gè)Sprint Backlog;

          4、Sprint Backlog是由Scrum Team去完成的,每個(gè)成員根據(jù)Sprint Backlog再細(xì)化成更小的任務(wù)(細(xì)到每個(gè)任務(wù)的工作量在2天內(nèi)能完成);

          5、在Scrum Team完成計(jì)劃會議上選出的Sprint Backlog過程中,需要進(jìn)行 Daily Scrum Meeting(每日站立會議),每次會議控制在15分鐘左右,每個(gè)人都必須發(fā)言,并且要向所有成員當(dāng)面匯報(bào)你昨天完成了什么,并且向所有成員承諾你今天要完成什么,同時(shí)遇到不能解決的問題也可以提出,每個(gè)人回答完成后,要走到黑板前更新自己的 Sprint burn down(Sprint燃盡圖);

          6、做到每日集成,也就是每天都要有一個(gè)可以成功編譯、并且可以演示的版本;很多人可能還沒有用過自動化的每日集成,其實(shí)TFS就有這個(gè)功能,它可以支持每次有成員進(jìn)行簽入操作的時(shí)候,在服務(wù)器上自動獲取最新版本,然后在服務(wù)器中編譯,如果通過則馬上再執(zhí)行單元測試代碼,如果也全部通過,則將該版本發(fā)布,這時(shí)一次正式的簽入操作才保存到TFS中,中間有任何失敗,都會用郵件通知項(xiàng)目管理人員;

          7、當(dāng)一個(gè)Story完成,也就是Sprint Backlog被完成,也就表示一次Sprint完成,這時(shí),我們要進(jìn)行 Srpint Review Meeting(演示會議),也稱為評審會議,產(chǎn)品負(fù)責(zé)人和客戶都要參加(最好本公司老板也參加),每一個(gè)Scrum Team的成員都要向他們演示自己完成的軟件產(chǎn)品(這個(gè)會議非常重要,一定不能取消);

          8、最后就是 Sprint Retrospective Meeting(回顧會議),也稱為總結(jié)會議,以輪流發(fā)言方式進(jìn)行,每個(gè)人都要發(fā)言,總結(jié)并討論改進(jìn)的地方,放入下一輪Sprint的產(chǎn)品需求中;

           

           

          下面是運(yùn)用Scrum開發(fā)流程中的一些場景圖:

          上圖是一個(gè) Product Backlog 的示例。

           

          上圖就是每日的站立會議了,參會人員可以隨意姿勢站立,任務(wù)看板要保證讓每個(gè)人看到,當(dāng)每個(gè)人發(fā)言完后,要走到任務(wù)版前更新自己的燃盡圖。



          任務(wù)看版包含 未完成、正在做、已完成 的工作狀態(tài),假設(shè)你今天把一個(gè)未完成的工作已經(jīng)完成,那么你要把小卡片從未完成區(qū)域貼到已完成區(qū)域。


           

          每個(gè)人的工作進(jìn)度和完成情況都是公開的,如果有一個(gè)人的工作任務(wù)在某一個(gè)位置放了好幾天,大家都能發(fā)現(xiàn)他的工作進(jìn)度出現(xiàn)了什么問題(成員人數(shù)最好是5~7個(gè),這樣每人可以使用一種專用顏色的標(biāo)簽紙,一眼就可以從任務(wù)版看出誰的工作進(jìn)度快,誰的工作進(jìn)度慢)

           

           

           上圖可不是撲克牌,它是計(jì)劃紙牌,它的作用是防止項(xiàng)目在開發(fā)過程中,被某些人所領(lǐng)導(dǎo)。

          怎么用的呢?比如A程序員開發(fā)一個(gè)功能,需要5個(gè)小時(shí),B程序員認(rèn)為只需要半小時(shí),那他們各自取相應(yīng)的牌,藏在手中,最后攤牌,如果時(shí)間差距很大,那么A和B就可以討論A為什么要5個(gè)小時(shí)...
          轉(zhuǎn)自:http://www.cnblogs.com/taven/archive/2010/10/17/1853386.html

          posted @ 2016-04-28 11:14 小秦 閱讀(255) | 評論 (1)編輯 收藏

          悲觀鎖與樂觀鎖(轉(zhuǎn))

          先申明概念:

          1、悲觀鎖,正如其名,它指的是對數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度,因此,在整個(gè)數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機(jī)制(也只有數(shù)據(jù)庫層提供的鎖機(jī)制才能真正保證數(shù)據(jù)訪問的排他性,否則,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制,也無法保證外部系統(tǒng)不會修改數(shù)據(jù))。
          2、樂觀鎖( Optimistic Locking )
          相對悲觀鎖而言,樂觀鎖機(jī)制采取了更加寬松的加鎖機(jī)制。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機(jī)制實(shí)現(xiàn),以保證操作最大程度的獨(dú)占性。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷,特別是對長事務(wù)而言,這樣的開銷往往無法承受。而樂觀鎖機(jī)制在一定程度上解決了這個(gè)問題。樂觀鎖,大多是基于數(shù)據(jù)版本( Version )記錄機(jī)制實(shí)現(xiàn)。何謂數(shù)據(jù)版本?即為數(shù)據(jù)增加一個(gè)版本標(biāo)識,在基于數(shù)據(jù)庫表的版本解決方案中,一般是通過為數(shù)據(jù)庫表增加一個(gè) “version” 字段來實(shí)現(xiàn)。讀取出數(shù)據(jù)時(shí),將此版本號一同讀出,之后更新時(shí),對此版本號加一。此時(shí),將提交數(shù)據(jù)的版本數(shù)據(jù)與數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息進(jìn)行比對,如果提交的數(shù)據(jù)版本號大于數(shù)據(jù)庫表當(dāng)前版本號,則予以更新,否則認(rèn)為是過期數(shù)據(jù)。

          所以悲觀鎖和樂觀鎖最大的區(qū)別是是否一直鎖定資源,悲觀鎖在事物的全流程鎖定數(shù)據(jù),樂觀鎖不鎖定數(shù)據(jù)(用讀寫鎖是阻塞事物,而用樂觀鎖則會導(dǎo)致回滾。這個(gè)是一種事物沖突后的不同鎖的表象)。樂觀鎖的最大特點(diǎn)是在最后檢查數(shù)據(jù)是否被修改,如果已被別人修改過,則回滾數(shù)據(jù),避免臟數(shù)據(jù)。至于事物是否沖突和加鎖沒有直接聯(lián)系,該沖突的還是會沖突,不管你加悲觀鎖和樂觀鎖都會沖突。

          悲觀鎖和樂觀鎖都是為了解決丟失更新問題或者是臟讀。悲觀鎖和樂觀鎖的重點(diǎn)就是是否在讀取記錄的時(shí)候直接上鎖。悲觀鎖的缺點(diǎn)很明顯,需要一個(gè)持續(xù)的數(shù)據(jù)庫連接,這在web應(yīng)用中已經(jīng)不適合了。

          一個(gè)比較清楚的場景

          下面這個(gè)假設(shè)的實(shí)際場景可以比較清楚的幫助我們理解這個(gè)問題:

          a. 假設(shè)當(dāng)當(dāng)網(wǎng)上用戶下單買了本書,這時(shí)數(shù)據(jù)庫中有條訂單號為001的訂單,其中有個(gè)status字段是’有效’,表示該訂單是有效的;
          b. 后臺管理人員查詢到這條001的訂單,并且看到狀態(tài)是有效的
          c. 用戶發(fā)現(xiàn)下單的時(shí)候下錯了,于是撤銷訂單,假設(shè)運(yùn)行這樣一條SQL: update order_table set status = ‘取消’ where order_id = 001;
          d. 后臺管理人員由于在b這步看到狀態(tài)有效的,這時(shí),雖然用戶在c這步已經(jīng)撤銷了訂單,可是管理人員并未刷新界面,看到的訂單狀態(tài)還是有效的,于是點(diǎn)擊”發(fā)貨”按鈕,將該訂單發(fā)到物流部門,同時(shí)運(yùn)行類似如下SQL,將訂單狀態(tài)改成已發(fā)貨:update order_table set status = ‘已發(fā)貨’ where order_id = 001

          觀點(diǎn)1:只有沖突非常嚴(yán)重的系統(tǒng)才需要悲觀鎖;
          分析:這是更準(zhǔn)確的說法;
          “所有悲觀鎖的做法都適合于狀態(tài)被修改的概率比較高的情況,具體是否合適則需要根據(jù)實(shí)際情況判斷。”,表達(dá)的也是這個(gè)意思,不過說法不夠準(zhǔn)確;的確,之所以用悲觀鎖就是因?yàn)閮蓚€(gè)用戶更新同一條數(shù)據(jù)的概率高,也就是沖突比較嚴(yán)重的情況下,所以才用悲觀鎖。

          觀點(diǎn)2:最后提交前作一次select for update檢查,然后再提交update也是一種樂觀鎖的做法
          分析:這是更準(zhǔn)確的說法;
          的確,這符合傳統(tǒng)樂觀鎖的做法,就是到最后再去檢查。但是wiki在解釋悲觀鎖的做法的時(shí)候,’It is not appropriate for use in web application development.’, 現(xiàn)在已經(jīng)很少有悲觀鎖的做法了,所以我自己將這種二次檢查的做法也歸為悲觀鎖的變種,因?yàn)檫@在所有樂觀鎖里面,做法和悲觀鎖是最接近的,都是先select for update,然后update

          *****除了上面的觀點(diǎn)1和觀點(diǎn)2是更準(zhǔn)確的說法,下面的所有觀點(diǎn)都是錯誤的***********

          觀點(diǎn)3:這個(gè)問題的原因是因?yàn)閿?shù)據(jù)庫隔離級別是uncommitted read級別;
          分析:這個(gè)觀點(diǎn)是錯誤的;
          這個(gè)過程本身就是在read committed隔離級別下發(fā)生的,從a到d每一步,尤其是d這步,并不是因?yàn)樽x到了未提交的數(shù)據(jù),僅僅是因?yàn)橛脩艚缑鏇]有刷新[事實(shí)上也不可能做自動刷新,這樣相當(dāng)于數(shù)據(jù)庫一發(fā)生改變立刻要刷新了,這需要監(jiān)聽數(shù)據(jù)庫了,顯然這是簡單問題復(fù)雜化了];

          觀點(diǎn)4:悲觀鎖是指一個(gè)用戶在更新數(shù)據(jù)的時(shí)候,其他用戶不能讀取這條記錄;也就是update阻塞讀才叫悲觀鎖;
          分析:這個(gè)觀點(diǎn)是錯的;
          這在db2背景的開發(fā)中尤其常見;因?yàn)閐b2默認(rèn)就是update會阻塞讀;但是這是各個(gè)數(shù)據(jù)庫對讀寫的時(shí)候上鎖的并發(fā)處理實(shí)現(xiàn)不一樣。但這根本不是悲觀鎖樂觀鎖的區(qū)別。Oracle可以做到寫不阻塞讀僅僅是因?yàn)樽隽硕喟姹静l(fā)控制(Multiversion concurrency control), http://en.wikipedia.org/wiki/Multiversion_concurrency_control;但是在Oracle里面,一樣可以做樂觀鎖和悲觀鎖的控制。這本質(zhì)上是應(yīng)用層面的選擇。

          觀點(diǎn)5:Oracle實(shí)際上用的就是樂觀鎖
          分析:這個(gè)觀點(diǎn)是錯的;
          前面說了,Oracle的確可以做到寫不阻塞讀,但是這不是悲觀鎖和樂觀鎖的問題。這是因?yàn)閷?shí)現(xiàn)了多版本并發(fā)控制。按照wiki的定義,悲觀鎖和樂觀鎖是在應(yīng)用層面選擇的。Oracle的應(yīng)用只要在第二步做了select for update,就是悲觀鎖的做法;況且Oracle在任何隔離級別下,除了分布式事務(wù)兩階段提交的短暫時(shí)間,其他所有情況下都不存在寫阻塞讀的情況,如果按照這個(gè)觀點(diǎn)的話那Oracle已經(jīng)不能做悲觀鎖了-_-

          觀點(diǎn)6:不需要這么麻煩,只需要在d這步,最后提交更新的時(shí)候再做一個(gè)普通的select檢查一下就可以;[就是double check的做法]
          分析:這個(gè)觀點(diǎn)是錯的。
          這個(gè)做法其實(shí)在http://www.hetaoblog.com/database-lost-update-pessimistic-lock/,’3. 傳統(tǒng)悲觀鎖做法的變通’這節(jié)已經(jīng)說明了,如果要這么做的話,仍然需要在最后提交更新前double check的時(shí)候做一個(gè)select for update, 否則select結(jié)束到update提交前的時(shí)間仍然有可能記錄被修改;

          觀點(diǎn)7:應(yīng)該盡可能使用悲觀鎖;
          分析:這個(gè)觀點(diǎn)是錯的;
          a. 根據(jù)悲觀鎖的概念,用戶在讀的時(shí)候(b這步)就會將記錄鎖住,直到更新結(jié)束的時(shí)候才會將鎖釋放,所以整個(gè)鎖的過程時(shí)間比較長;
          b. 另外,悲觀鎖需要有一個(gè)持續(xù)的數(shù)據(jù)庫連接,這在當(dāng)今的web應(yīng)用中已經(jīng)幾乎不存在;wiki上也說了, 悲觀鎖‘is not appropriate for use in web application development.’

          所以,現(xiàn)在大部分應(yīng)用都應(yīng)該是樂觀鎖的;
          轉(zhuǎn)自:http://zhidao.baidu.com/link?url=MUOUg59oz7-FKwz-zuUviGryfw9J4V63Pd2iWWErorwUpyeL85rznlmYaGDHXjH_ChywA3R1m9XNpx4k7RCCT3rNofjkCxIBYHdsvwr2bVy

          posted @ 2016-01-05 09:32 小秦 閱讀(338) | 評論 (0)編輯 收藏

          Lock和synchronized (轉(zhuǎn))

              JDK1.5以后,在鎖機(jī)制方面引入了新的鎖-Lock,在網(wǎng)上的說法都比較籠統(tǒng),結(jié)合網(wǎng)上的信息和我的理解這里做個(gè)總結(jié)。 

              java現(xiàn)有的鎖機(jī)制有兩種實(shí)現(xiàn)方式,J.DK1.4前是通過synchronized實(shí)現(xiàn),JDK1.5后加入java.util.concurrent.locks包下的各種lock(以下簡稱Lock) 

              先說說代碼層的區(qū)別。 
              synchronized:在代碼里,synchronized類似“面向?qū)ο?#8221;,修飾類、方法、對象。 
              Lock:不作為修飾,類似“面向過程”,在方法中需要鎖的時(shí)候lock,在結(jié)束的時(shí)候unlock(一般都在finally塊里)。 
          例如代碼: 

          Java代碼  收藏代碼
          1. public void method1() {  
          2.     synchronized(this){//舊鎖,無需人工釋放  
          3.         System.out.println(1);  
          4.     }  
          5. }  
          6.       
          7. public void method2() {  
          8.     Lock lock = new ReentrantLock();  
          9.     lock.lock();//上鎖  
          10.     try{  
          11.         System.out.println(2);  
          12.     }finally{  
          13.         lock.unlock();//解鎖  
          14.     }  
          15. }  

              其次說說性能。 
              相關(guān)的性能測試網(wǎng)上已經(jīng)有很多,這里也直接拿來主義,給出結(jié)論: 
              在并發(fā)高是,luck性能優(yōu)勢很明顯,在低并發(fā)時(shí),synchronized也能取得優(yōu)勢。具體的臨界范圍比較難定論,下面會討論。 

              現(xiàn)在來分析它們具體的區(qū)別。 
              鎖都是 原子性 的,也可以理解為鎖是否在使用的標(biāo)記,并且比較和設(shè)置這個(gè)標(biāo)記的操作是原子性的,不同硬件平臺上的jdk實(shí)現(xiàn)鎖的相關(guān)方法都是native的(比如park/unpark),所以不同平臺上鎖的精確度的等級由這些native的方法決定。所以網(wǎng)上經(jīng)常可以看見的結(jié)論是“Lock比synchronized有更精確的原子操作”說的也是native方法(不得不感慨C才是硬件王道)。 


          下面繼續(xù)討論怎么由代碼層到native的過程。 
          1、所有對象都自動含有單一的鎖,JVM負(fù)責(zé)跟蹤對象被加鎖的次數(shù)。如果一個(gè)對象被解鎖,其計(jì)數(shù)變?yōu)?。在任務(wù)(線程)第一次給對象加鎖的時(shí)候,計(jì)數(shù)變?yōu)?。每當(dāng)這個(gè)相同的任務(wù)(線程)在此對象上獲得鎖時(shí),計(jì)數(shù)會遞增。 只有首先獲得鎖的任務(wù)(線程)才能繼續(xù)獲取該對象上的多個(gè)鎖。每當(dāng)任務(wù)離開時(shí),計(jì)數(shù)遞減,當(dāng)計(jì)數(shù)為0的時(shí)候,鎖被完全釋放。synchronized就是基于這個(gè)原理,同時(shí)synchronized靠某個(gè)對象的單一鎖技術(shù)的次數(shù)來判斷是否被鎖,所以無需(也不能)人工干預(yù)鎖的獲取和釋放。如果結(jié)合方法調(diào)用時(shí)的棧和框架(如果對方法的調(diào)用過程不熟悉建議看看http://wupuyuan.iteye.com/blog/1157548),不難推測出synchronized原理是基于棧中的某對象來控制一個(gè)框架,所以對于synchronized有常用的優(yōu)化是鎖對象不鎖方法。實(shí)際上synchronized作用于方法時(shí),鎖住的是“this”,作用于靜態(tài)方法/屬性時(shí),鎖住的是存在于永久帶的CLASS,相當(dāng)于這個(gè)CLASS的全局鎖,鎖作用于一般對象時(shí),鎖住的是對應(yīng)代碼塊。在HotSpot中JVM實(shí)現(xiàn)中,鎖有個(gè)專門的名字:對象監(jiān)視器。 


          當(dāng)多個(gè)線程同時(shí)請求某個(gè)對象監(jiān)視器時(shí),對象監(jiān)視器會設(shè)置幾種狀態(tài)用來區(qū)分請求的線程 
          Contention List:所有請求鎖的線程將被首先放置到該競爭隊(duì)列,是個(gè)虛擬隊(duì)列,不是實(shí)際的Queue的數(shù)據(jù)結(jié)構(gòu)。
          Entry List:EntryList與ContentionList邏輯上同屬等待隊(duì)列,ContentionList會被線程并發(fā)訪問,為了降低對ContentionList隊(duì)尾的爭用,而建立EntryList。,Contention List中那些有資格成為候選人的線程被移到Entry List 
          Wait Set:那些調(diào)用wait方法被阻塞的線程被放置到Wait Set 
          OnDeck:任何時(shí)刻最多只能有一個(gè)線程正在競爭鎖,該線程稱為OnDeck 
          Owner:獲得鎖的線程稱為Owner 
          !Owner:釋放鎖的線程 

          2、Lock不同于synchronized面向?qū)ο螅跅V械目蚣芏皇悄硞€(gè)具體對象,所以Lock只需要在棧里設(shè)置鎖的開始和結(jié)束(lock和unlock)的地方就行了(人工必須標(biāo)明),不用關(guān)心框架大小對象的變化等等。這么做的好處是Lock能提供無條件的、可輪詢的、定時(shí)的、可中斷的鎖獲取操作,相對于synchronized來說,synchronized的鎖的獲取是釋放必須在一個(gè)模塊里,獲取和釋放的順序必須相反,而Lock則可以在不同范圍內(nèi)獲取釋放,并且順序無關(guān)。java.util.concurrent.locks下的鎖類很類似,依賴于java.util.concurrent.AbstractQueuedSynchronizer,它們把所有的Lock接口操作都轉(zhuǎn)嫁到Sync類上,這個(gè)類繼承了AbstractQueuedSynchronizer,它同時(shí)還包含子2個(gè)類:NonfairSync 和FairSync 從名字上可以看的出是為了實(shí)現(xiàn)公平和非公平性。AbstractQueuedSynchronizer中把所有的的請求線程構(gòu)成一個(gè)隊(duì)列(一樣也是虛擬的),具體的實(shí)現(xiàn)可以參考http://blog.csdn.net/chen77716/article/details/6641477#,這里我就不復(fù)制了。 

          3、從jdk的源代碼來看,Lock和synchronized的源碼基本相同,區(qū)別主要在維護(hù)的同步隊(duì)列上。再往下深究就到了native方法了。 

          4、還有個(gè)改進(jìn)我也想說下,其實(shí)很重要的。線程分阻塞(wait)和非阻塞狀態(tài),阻塞狀態(tài)由操作系統(tǒng)(linux、windows等)完成,當(dāng)前一個(gè)被“鎖”的線程執(zhí)行完畢后,有可能在后續(xù)的線程隊(duì)列里還沒分配出一個(gè)獲取鎖而被“喚醒”的非阻塞線程,即所有線程還都是阻塞狀態(tài)時(shí),就被系統(tǒng)調(diào)度(進(jìn)入內(nèi)核的線程是阻塞的),這樣會導(dǎo)致內(nèi)核在用戶態(tài)和內(nèi)核態(tài)之間來回接換,嚴(yán)重影響鎖的性能。在jdk1.6以前主要靠自旋鎖來解決,原理是在前一個(gè)線程結(jié)束后,爭用線程可以做一個(gè)空循環(huán),繼續(xù)占有CPU,等待取鎖的機(jī)會。當(dāng)然這樣做顯然也是浪費(fèi)時(shí)間,只是在兩種浪費(fèi)中選取浪費(fèi)少的……  jdk1.6后引入了偏向鎖,當(dāng)線程第一次獲得了監(jiān)視對象,之后讓監(jiān)視對象“偏向”這個(gè)線程,之后的多次調(diào)用則可以避免CAS操作,等于是置了一臨時(shí)變量來記錄位置(類似索引比較)。詳細(xì)的就涉及到匯編指令了,我也就沒太深究,偏向鎖性能優(yōu)于自旋鎖,但是還是沒有達(dá)到HotSpot認(rèn)為的最佳時(shí)間(一個(gè)線程上下文切換的時(shí)間)。 

              綜合來看對于所有的高并發(fā)情況,采用Lock加鎖是最優(yōu)選擇,但是由于歷史遺留等問題,synchronized也還是不能完全被淘汰,同時(shí),在低并發(fā)情況下,synchronized的性能還是比Lock好的。 

          原帖地址:http://wupuyuan.iteye.com/blog/1158655

          posted @ 2015-10-27 19:08 小秦 閱讀(313) | 評論 (0)編輯 收藏

          再敘TIME_WAIT(轉(zhuǎn))

          再敘TIME_WAIT


          之所以起這樣一個(gè)題目是因?yàn)楹芫靡郧拔以?jīng)寫過一篇介紹TIME_WAIT的文章,不過當(dāng)時(shí)基本屬于淺嘗輒止,并沒深入說明問題的來龍去脈,碰巧這段時(shí)間反復(fù)被別人問到相關(guān)的問題,讓我覺得有必要全面總結(jié)一下,以備不時(shí)之需。

          討論前大家可以拿手頭的服務(wù)器摸摸底,記住「ss」比「netstat」快:

          shell> ss -ant | awk '     NR>1 {++s[$1]} END {for(k in s) print k,s[k]} '

          如果你只是想單獨(dú)查詢一下TIME_WAIT的數(shù)量,那么還可以更簡單一些:

          shell> cat /proc/net/sockstat

          我猜你一定被巨大無比的TIME_WAIT網(wǎng)絡(luò)連接總數(shù)嚇到了!以我個(gè)人的經(jīng)驗(yàn),對于一臺繁忙的Web服務(wù)器來說,如果主要以短連接為主,那么其TIME_WAIT網(wǎng)絡(luò)連接總數(shù)很可能會達(dá)到幾萬,甚至十幾萬。雖然一個(gè)TIME_WAIT網(wǎng)絡(luò)連接耗費(fèi)的資源無非就是一個(gè)端口、一點(diǎn)內(nèi)存,但是架不住基數(shù)大,所以這始終是一個(gè)需要面對的問題。

          為什么會存在TIME_WAIT?

          TCP在建立連接的時(shí)候需要握手,同理,在關(guān)閉連接的時(shí)候也需要握手。為了更直觀的說明關(guān)閉連接時(shí)握手的過程,我們引用「The TCP/IP Guide」中的例子

          TCP Close

          TCP Close

          因?yàn)門CP連接是雙向的,所以在關(guān)閉連接的時(shí)候,兩個(gè)方向各自都需要關(guān)閉。先發(fā)FIN包的一方執(zhí)行的是主動關(guān)閉;后發(fā)FIN包的一方執(zhí)行的是被動關(guān)閉。主動關(guān)閉的一方會進(jìn)入TIME_WAIT狀態(tài),并且在此狀態(tài)停留兩倍的MSL時(shí)長。

          穿插一點(diǎn)MSL的知識:MSL指的是報(bào)文段的最大生存時(shí)間,如果報(bào)文段在網(wǎng)絡(luò)活動了MSL時(shí)間,還沒有被接收,那么會被丟棄。關(guān)于MSL的大小,RFC 793協(xié)議中給出的建議是兩分鐘,不過實(shí)際上不同的操作系統(tǒng)可能有不同的設(shè)置,以Linux為例,通常是半分鐘,兩倍的MSL就是一分鐘,也就是60秒,并且這個(gè)數(shù)值是硬編碼在內(nèi)核中的,也就是說除非你重新編譯內(nèi)核,否則沒法修改它:

          #define TCP_TIMEWAIT_LEN (60*HZ)

          如果每秒的連接數(shù)是一千的話,那么一分鐘就可能會產(chǎn)生六萬個(gè)TIME_WAIT。

          為什么主動關(guān)閉的一方不直接進(jìn)入CLOSED狀態(tài),而是進(jìn)入TIME_WAIT狀態(tài),并且停留兩倍的MSL時(shí)長呢?這是因?yàn)門CP是建立在不可靠網(wǎng)絡(luò)上的可靠的協(xié)議。例子:主動關(guān)閉的一方收到被動關(guān)閉的一方發(fā)出的FIN包后,回應(yīng)ACK包,同時(shí)進(jìn)入TIME_WAIT狀態(tài),但是因?yàn)榫W(wǎng)絡(luò)原因,主動關(guān)閉的一方發(fā)送的這個(gè)ACK包很可能延遲,從而觸發(fā)被動連接一方重傳FIN包。極端情況下,這一去一回,就是兩倍的MSL時(shí)長。如果主動關(guān)閉的一方跳過TIME_WAIT直接進(jìn)入CLOSED,或者在TIME_WAIT停留的時(shí)長不足兩倍的MSL,那么當(dāng)被動關(guān)閉的一方早先發(fā)出的延遲包到達(dá)后,就可能出現(xiàn)類似下面的問題:

          • 舊的TCP連接已經(jīng)不存在了,系統(tǒng)此時(shí)只能返回RST包
          • 新的TCP連接被建立起來了,延遲包可能干擾新的連接

          不管是哪種情況都會讓TCP不再可靠,所以TIME_WAIT狀態(tài)有存在的必要性。

          如何控制TIME_WAIT的數(shù)量?

          從前面的描述我們可以得出這樣的結(jié)論:TIME_WAIT這東西沒有的話不行,不過太多可能也是個(gè)麻煩事。下面讓我們看看有哪些方法可以控制TIME_WAIT數(shù)量,這里只說一些常規(guī)方法,另外一些諸如SO_LINGER之類的方法太過偏門,略過不談。

          ip_conntrack:顧名思義就是跟蹤連接。一旦激活了此模塊,就能在系統(tǒng)參數(shù)里發(fā)現(xiàn)很多用來控制網(wǎng)絡(luò)連接狀態(tài)超時(shí)的設(shè)置,其中自然也包括TIME_WAIT:

          shell> modprobe ip_conntrack shell> sysctl net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait

          我們可以嘗試縮小它的設(shè)置,比如十秒,甚至一秒,具體設(shè)置成多少合適取決于網(wǎng)絡(luò)情況而定,當(dāng)然也可以參考相關(guān)的案例。不過就我的個(gè)人意見來說,ip_conntrack引入的問題比解決的還多,比如性能會大幅下降,所以不建議使用。

          tcp_tw_recycle:顧名思義就是回收TIME_WAIT連接。可以說這個(gè)內(nèi)核參數(shù)已經(jīng)變成了大眾處理TIME_WAIT的萬金油,如果你在網(wǎng)絡(luò)上搜索TIME_WAIT的解決方案,十有八九會推薦設(shè)置它,不過這里隱藏著一個(gè)不易察覺的陷阱

          當(dāng)多個(gè)客戶端通過NAT方式聯(lián)網(wǎng)并與服務(wù)端交互時(shí),服務(wù)端看到的是同一個(gè)IP,也就是說對服務(wù)端而言這些客戶端實(shí)際上等同于一個(gè),可惜由于這些客戶端的時(shí)間戳可能存在差異,于是乎從服務(wù)端的視角看,便可能出現(xiàn)時(shí)間戳錯亂的現(xiàn)象,進(jìn)而直接導(dǎo)致時(shí)間戳小的數(shù)據(jù)包被丟棄。參考:tcp_tw_recycle和tcp_timestamps導(dǎo)致connect失敗問題

          tcp_tw_reuse:顧名思義就是復(fù)用TIME_WAIT連接。當(dāng)創(chuàng)建新連接的時(shí)候,如果可能的話會考慮復(fù)用相應(yīng)的TIME_WAIT連接。通常認(rèn)為「tcp_tw_reuse」比「tcp_tw_recycle」安全一些,這是因?yàn)橐粊鞹IME_WAIT創(chuàng)建時(shí)間必須超過一秒才可能會被復(fù)用;二來只有連接的時(shí)間戳是遞增的時(shí)候才會被復(fù)用。官方文檔里是這樣說的:如果從協(xié)議視角看它是安全的,那么就可以使用。這簡直就是外交辭令啊!按我的看法,如果網(wǎng)絡(luò)比較穩(wěn)定,比如都是內(nèi)網(wǎng)連接,那么就可以嘗試使用。

          不過需要注意的是在哪里使用,既然我們要復(fù)用連接,那么當(dāng)然應(yīng)該在連接的發(fā)起方使用,而不能在被連接方使用。舉例來說:客戶端向服務(wù)端發(fā)起HTTP請求,服務(wù)端響應(yīng)后主動關(guān)閉連接,于是TIME_WAIT便留在了服務(wù)端,此類情況使用「tcp_tw_reuse」是無效的,因?yàn)榉?wù)端是被連接方,所以不存在復(fù)用連接一說。讓我們延伸一點(diǎn)來看,比如說服務(wù)端是PHP,它查詢另一個(gè)MySQL服務(wù)端,然后主動斷開連接,于是TIME_WAIT就落在了PHP一側(cè),此類情況下使用「tcp_tw_reuse」是有效的,因?yàn)榇藭r(shí)PHP相對于MySQL而言是客戶端,它是連接的發(fā)起方,所以可以復(fù)用連接。

          說明:如果使用tcp_tw_reuse,請激活tcp_timestamps,否則無效。

          tcp_max_tw_buckets:顧名思義就是控制TIME_WAIT總數(shù)。官網(wǎng)文檔說這個(gè)選項(xiàng)只是為了阻止一些簡單的DoS攻擊,平常不要人為的降低它。如果縮小了它,那么系統(tǒng)會將多余的TIME_WAIT刪除掉,日志里會顯示:「TCP: time wait bucket table overflow」。

          需要提醒大家的是物極必反,曾經(jīng)看到有人把「tcp_max_tw_buckets」設(shè)置成0,也就是說完全拋棄TIME_WAIT,這就有些冒險(xiǎn)了,用一句圍棋諺語來說:入界宜緩。

          有時(shí)候,如果我們換個(gè)角度去看問題,往往能得到四兩撥千斤的效果。前面提到的例子:客戶端向服務(wù)端發(fā)起HTTP請求,服務(wù)端響應(yīng)后主動關(guān)閉連接,于是TIME_WAIT便留在了服務(wù)端。這里的關(guān)鍵在于主動關(guān)閉連接的是服務(wù)端!在關(guān)閉TCP連接的時(shí)候,先出手的一方注定逃不開TIME_WAIT的宿命,套用一句歌詞:把我的悲傷留給自己,你的美麗讓你帶走。如果客戶端可控的話,那么在服務(wù)端打開KeepAlive,盡可能不讓服務(wù)端主動關(guān)閉連接,而讓客戶端主動關(guān)閉連接,如此一來問題便迎刃而解了。

          參考文檔:

          1. tcp短連接TIME_WAIT問題解決方法大全(1)——高屋建瓴
          2. tcp短連接TIME_WAIT問題解決方法大全(2)——SO_LINGER
          3. tcp短連接TIME_WAIT問題解決方法大全(3)——tcp_tw_recycle
          4. tcp短連接TIME_WAIT問題解決方法大全(4)——tcp_tw_reuse
          5. tcp短連接TIME_WAIT問題解決方法大全(5)——tcp_max_tw_buckets

          轉(zhuǎn)自http://huoding.com/2013/12/31/316

          posted @ 2015-10-16 14:28 小秦 閱讀(256) | 評論 (0)編輯 收藏

          網(wǎng)絡(luò)安全與維護(hù)

          1、常規(guī)網(wǎng)絡(luò)訪問限制:
          a、線上運(yùn)營設(shè)備的SSH端口不允許綁定在公網(wǎng)IP地址上,開發(fā)只能登錄開發(fā)機(jī)然后通過內(nèi)網(wǎng)登錄這些服務(wù)器;
          b、開發(fā)機(jī)、測試機(jī)的SSH端口可以綁定在公網(wǎng)IP地址上,SSH端口(22)可以考慮改為非知名端口;
          c、線上運(yùn)營設(shè)備、開發(fā)機(jī)、測試機(jī)的防火墻配置,公網(wǎng)只做80(HTTP)、8080(HTTP)、443(HTTPS)、SSH端口(僅限開發(fā)機(jī)、測試機(jī))對外授權(quán)訪問;
          d、線上運(yùn)營設(shè)備、開發(fā)機(jī)、測試機(jī)除第c點(diǎn)以外所有服務(wù)端口禁止綁定在公網(wǎng)IP地址上,尤其是3306端口(MySQL);
          2、DB保護(hù),
          a、DB服務(wù)器不允許配置公網(wǎng)IP(或用防火墻全部禁止公網(wǎng)訪問);
          b、DB的root賬戶不用于業(yè)務(wù)訪問,回收集中管理,開放普通賬戶做業(yè)務(wù)邏輯訪問,對不同安全要求的庫表用不同的賬戶密碼訪問;
          c、程序不要把DB訪問的賬戶密碼寫到配置文件中,寫入代碼或啟動時(shí)遠(yuǎn)程到配置中心拉取(此方法比較重,可暫不考慮)。
          d、另:DB備份文件可以考慮做加密處理;
          3、系統(tǒng)安全:
          a、設(shè)備的root密碼回收集中管理,給開發(fā)提供普通用戶帳號;
          b、密碼需要定期修改,有強(qiáng)度要求;
          4、業(yè)務(wù)訪問控制:
          a、業(yè)務(wù)服務(wù)邏輯和運(yùn)營平臺,盡量不要提供對用戶表和訂單表的批量訪問接口,如果運(yùn)營平臺確實(shí)有這樣的需求,需要對特定賬戶做授權(quán);
          安全的代價(jià)是不方便、效率會下降,需要尋找平衡點(diǎn)。 

          posted @ 2015-10-16 13:45 小秦 閱讀(310) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 营山县| 镇沅| 安仁县| 永定县| 邢台县| 陆丰市| 仁布县| 大港区| 杭锦后旗| 丰城市| 宜宾县| 景泰县| 望奎县| 临朐县| 高安市| 交城县| 连南| 安塞县| 从江县| 龙里县| 婺源县| 忻州市| 仪陇县| 稷山县| 远安县| 江都市| 广南县| 长丰县| 金塔县| 抚州市| 红原县| 温宿县| 伊川县| 宁强县| 屯留县| 柳林县| 东港市| 大城县| 临泉县| 瑞安市| 石楼县|