2009年12月18日
搜索了一下,應(yīng)該是非正常關(guān)機(jī)導(dǎo)致eclipse工作區(qū)的文件狀態(tài)錯(cuò)誤導(dǎo)致。在工作區(qū)目錄中,有一個(gè).metadata目錄,里面是工作區(qū)及各插件的信息,刪除此目錄可以解決問題。
為保險(xiǎn)起見,將.metadata改名移動(dòng)到/tmp目錄,再重啟eclipse,果然可以正常啟動(dòng)eclipse了,但原來工作區(qū)的配置和項(xiàng)目信息也都消失,直接顯示的是歡迎界面。
如何恢復(fù)原來的project配置呢?嘗試對(duì)比了當(dāng)前的.metadata和之前備份的那個(gè)目錄,發(fā)現(xiàn)缺少了很多配置文件。試著一點(diǎn)點(diǎn)恢復(fù)一些目錄,但效 果不理想。因?yàn)椴恢滥男┪募?目錄)可以恢復(fù),哪些恢復(fù)會(huì)帶來問題。將備份的整個(gè)目錄恢復(fù)試試?Eclipse又回到了無法啟動(dòng)的狀態(tài)了。
怎么辦?這時(shí)想到啟動(dòng)停止時(shí)顯示的狀態(tài):"Loading workbench",看來和這個(gè)workbench插件有關(guān)。查看原來的.metadata/.plugins目錄,在眾多文件夾中
com.collabnet.subversion.merge org.eclipse.search
org.eclipse.compare org.eclipse.team.core
org.eclipse.core.resources org.eclipse.team.cvs.core
org.eclipse.core.runtime org.eclipse.team.ui
org.eclipse.debug.core org.eclipse.ui.ide
org.eclipse.debug.ui org.eclipse.ui.intro
org.eclipse.dltk.core org.eclipse.ui.views.log
org.eclipse.dltk.core.index.sql.h2 org.eclipse.ui.workbench
org.eclipse.dltk.ui org.eclipse.ui.workbench.texteditor
org.eclipse.epp.usagedata.recording org.eclipse.wb.discovery.core
org.eclipse.jdt.core org.eclipse.wst.internet.cache
org.eclipse.jdt.ui org.eclipse.wst.jsdt.core
org.eclipse.ltk.core.refactoring org.eclipse.wst.jsdt.ui
org.eclipse.ltk.ui.refactoring org.eclipse.wst.jsdt.web.core
org.eclipse.m2e.core org.eclipse.wst.sse.ui
org.eclipse.m2e.logback.configuration org.eclipse.wst.validation
org.eclipse.mylyn.bugzilla.core org.eclipse.wst.xml.core
org.eclipse.mylyn.tasks.ui org.tigris.subversion.subclipse.core
org.eclipse.php.core org.tigris.subversion.subclipse.graph
org.eclipse.php.ui org.tigris.subversion.subclipse.ui
發(fā)現(xiàn)了兩個(gè): org.eclipse.ui.workbench 和 org.eclipse.ui.workbench.texteditor。
不管三七二十一,刪了這兩個(gè)目錄,重新啟動(dòng)eclipse。正常啟動(dòng)且原項(xiàng)目信息正確加載。
轉(zhuǎn)自:作者: Fenng | 可以轉(zhuǎn)載, 但必須以超鏈接形式標(biāo)明文章原始出處和作者信息及版權(quán)聲明
網(wǎng)址: http://www.dbanotes.net/startup/small_problem_big_problem.html
最近團(tuán)隊(duì)遇到一個(gè)案例。看似很小的事情,但仔細(xì)研究起來,徹底分析,每一個(gè)環(huán)節(jié)都沒做好,細(xì)節(jié)部分糟糕得一塌糊涂,最后導(dǎo)致一件事情的結(jié)果:完全失敗。
經(jīng)常有人在聊起公司的時(shí)候問我,你現(xiàn)在最擔(dān)心的事情有哪些? 我當(dāng)然會(huì)重點(diǎn)提到團(tuán)隊(duì)。不過在談及團(tuán)隊(duì)的時(shí)候,我又最擔(dān)心在「細(xì)節(jié)」問題上做不好。
細(xì)節(jié)就是競(jìng)爭(zhēng)力,尤其是對(duì)小團(tuán)隊(duì)來說,小團(tuán)隊(duì)更應(yīng)該注重細(xì)節(jié)問題。大一點(diǎn)的公司可以追究責(zé)任人,靠流程、靠制度,靠各級(jí)評(píng)審等等一系列的「成本」來提升細(xì)節(jié)能力。小一點(diǎn)的公司或者團(tuán)隊(duì)怎么辦? 恐怕只有依賴每個(gè)人的能力和責(zé)任心了。
細(xì)節(jié)也是鍛煉人的能力的地方,搞清楚每一個(gè)細(xì)節(jié),將每一個(gè)細(xì)節(jié)涉及到的背景知識(shí)和技能掌握好,能力自然也就會(huì)得到提升。繼而,著手做更大的事情也不 會(huì)手忙腳亂。相反,做不好細(xì)節(jié)和小事的人,如果總?cè)轮觥钢匾沟氖虑椋龈小柑魬?zhàn)」的事情,這樣的事情真的到你面前,真的能接住么?
為什么我們?cè)诩?xì)節(jié)上做不好?
對(duì)細(xì)節(jié)問題不夠重視 一件事情到了自己這里,頭腦中先入為主認(rèn)為只是一件小事,是一件簡(jiǎn)單的事情。這樣,當(dāng)然就不會(huì)給予足夠的重視。小事不一定不重要,小事不一定意味著做起來就簡(jiǎn)單。
對(duì)事情復(fù)雜度缺乏認(rèn)知 不就是給客戶寫一封電子郵件么? 不就是用 HTML 寫一個(gè)頁面么? 不就是做一則橫幅廣告么? 那么,這些事情真的簡(jiǎn)單么? 為什么別人為客戶寫的郵件打開率更高? 為什么別人寫的頁面更容易被搜索引擎收錄? 為什么別人做的廣告轉(zhuǎn)化率更好? 背后涉及到哪些知識(shí)? 不想研究一下么? 不能研究一下么?
對(duì)細(xì)節(jié)缺乏耐心 草草了事,應(yīng)付了事,遇到問題馬馬虎虎,輕易得放過了很多可以讓自己得到成長的機(jī)會(huì)。「這問題我沒想過」「這事情我沒遇到過」「設(shè)計(jì)稿都改過兩次了」... 這類借口在任何一個(gè)團(tuán)隊(duì)都很常見。
缺少責(zé)任心 常常覺得自己這里做不好,還有別人會(huì)把關(guān)呢。擔(dān)心什么? 可如果所有人都這么想呢? 「文案是產(chǎn)品經(jīng)理的事情,關(guān)我甚么事?」如果你能對(duì)文案也有改進(jìn)意見,誰說以后你就不能做產(chǎn)品經(jīng)理做的事情呢?
主觀上不認(rèn)可自己的工作 就給我這么一點(diǎn)錢,要我做這么多工作? 問題是我們?nèi)绻欢嘧鲆稽c(diǎn)工作,不提升一下自己,又怎么能多一點(diǎn)錢呢?
為什么細(xì)節(jié)上做不好? 不同人不同的角度還會(huì)有不同的看法。不過有一點(diǎn)我能肯定,細(xì)節(jié)不會(huì)決定成敗,但做不好細(xì)節(jié),一定會(huì)失敗。
做好細(xì)節(jié),百事可作。
https://developer.apple.com/downloads/index.action
Documentation and developer runtime of "Java for OS X 2012-005". Contains JavaDoc, tools documentation, and native framework headers.
目前的版本是:Java for OS X 2012-005 Developer Package
下載下來后,直接安裝,默認(rèn)設(shè)置就可以了,然后可以建個(gè)link,方便選擇。
- sudo -s
- cd /System/Library/Frameworks/JavaVM.framework/Home
- ln -s /Library/Java/JavaVirtualMachines/1.6.0_35-b10-428.jdk/Contents/Home/docs.jar
- ln -s /Library/Java/JavaVirtualMachines/1.6.0_35-b10-428.jdk/Contents/Home/src.jar
- 最后跟windows類似,在eclipse中用command + click點(diǎn)擊查看一個(gè)類的源碼。然后選“add source",選中上面的 src.jar 文件即可
我平常學(xué)習(xí)android用的2.2版本,從網(wǎng)上下載了2.2的源碼(從官方git庫下載太麻煩,是從網(wǎng)友共享的源碼位置下載的).按照網(wǎng)上的說法,我把 解壓后的那一堆文檔放在了android-sdk-root\platforms\android-8\sources目錄下.不過并沒有重啟 eclipse.而是通過這種方法來做的-----在eclipse中,鼠標(biāo)放在一個(gè)android提供的類上,按下ctrl鍵,會(huì)打開一個(gè)新頁面,提示 找不到對(duì)應(yīng)的類的class或者源文件,但這個(gè)新頁面上有個(gè)導(dǎo)入源碼的按鈕,點(diǎn)擊之后選擇下載好的source位置,確定后就可以了.
順便說下我下載android源碼的位置:
http://tech.cncms.com/UploadFiles/20101025/androidsdk2.2_sources.zip
下載源碼到maven倉庫: http://search.maven.org/#search|gav|1|g%3A%22com.google.android%22%20AND%20a%3A%22android%22
1. 使用工具:微博第三方插件已經(jīng)提供了很多功能,適合自己的都用起來,這個(gè)我覺得最節(jié)省我的時(shí)間,其他網(wǎng)上提供的軟件都可以使用,重要是適合自己,安全第一。
2. 寫工具:有很多個(gè)性化需求的時(shí)候,如果變相的不能實(shí)現(xiàn),人為處理太慢太花時(shí)間,我們現(xiàn)在是小創(chuàng)業(yè)團(tuán)隊(duì),很多事情都需要自己做,數(shù)據(jù)增長慢,在有限的資源下,寫工具是非常好的方式,作為技術(shù)人員就直接動(dòng)手寫,當(dāng)然也需要看看性價(jià)比。
4.主要工作流程:(這個(gè)圖是轉(zhuǎn)的)
5.常用的微博話題(這個(gè)圖片也是轉(zhuǎn)的)
7.微博運(yùn)營最重要的是:一段時(shí)間需要總結(jié)挑選合適的方法執(zhí)行,沒有效果的去除。
如:微博發(fā)布時(shí)間/數(shù)量
JMock是幫助創(chuàng)建mock對(duì)象的工具,它基于Java開發(fā),在Java測(cè)試與開發(fā)環(huán)境中有不可比擬的優(yōu)勢(shì),更重要的是,它大大簡(jiǎn)化了虛擬對(duì)象的使用。本文中,通過一個(gè)簡(jiǎn)單的測(cè)試用例來說明JMock如何幫助我們實(shí)現(xiàn)這種孤立測(cè)試。
我們?cè)跍y(cè)試某類時(shí),由于它要與其他類發(fā)生聯(lián)系,因此往往在測(cè)試此類的代碼中也將與之聯(lián)系的類也一起測(cè)試了。這種測(cè)試,將使被測(cè)試的類直接依賴于其他類,一旦其他類發(fā)生改變,被測(cè)試類也隨之被迫改變。更重要的是,這些其他類可能尚未經(jīng)過測(cè)試,因此必須先測(cè)試這些類,才能測(cè)試被測(cè)試類。這種情況下,測(cè)試驅(qū)動(dòng)開發(fā)成為空談。而如果其他類中也引用了被測(cè)試類,我們到底先測(cè)試哪一個(gè)類?因此,在測(cè)試中,如果我們能將被測(cè)試類孤立起來,使其完全不依賴于其他類的具體實(shí)現(xiàn),這樣,我們就能做到測(cè)試先行,先測(cè)試哪個(gè)類,就先實(shí)現(xiàn)哪個(gè)類,而不管與之聯(lián)系的類是否已經(jīng)實(shí)現(xiàn)。
虛擬對(duì)象(mock object)就是為此需要而誕生的。它通過JDK中的反射機(jī)制,在運(yùn)行時(shí)動(dòng)態(tài)地創(chuàng)建虛擬對(duì)象。在測(cè)試代碼中,我們可以驗(yàn)證這些虛擬對(duì)象是否被正確地調(diào)用了,也可以在明確的情況下,讓其返回特定的假想值。而一旦有了這些虛擬對(duì)象提供的服務(wù),被測(cè)試類就可以將虛擬對(duì)象作為其他與之聯(lián)系的真實(shí)對(duì)象的替身,從而輕松地搭建起一個(gè)很完美的測(cè)試環(huán)境。
JMock是幫助創(chuàng)建mock對(duì)象的工具,它基于Java開發(fā),在Java測(cè)試與開發(fā)環(huán)境中有不可比擬的優(yōu)勢(shì),更重要的是,它大大簡(jiǎn)化了虛擬對(duì)象的使用。
本文中,通過一個(gè)簡(jiǎn)單的測(cè)試用例來說明JMock如何幫助我們實(shí)現(xiàn)這種孤立測(cè)試。有三個(gè)主要的類,User,UserDAO,及UserService。本文中,我們只需測(cè)試UserService,準(zhǔn)備虛擬UserDAO。對(duì)于User,由于本身僅是一個(gè)過于簡(jiǎn)單的POJO,可以不用測(cè)試。但如果你是一個(gè)完美主義者,也可以使用JMock的虛擬它。在這領(lǐng)域,JMock幾乎無所不能。
這里我用到的是:(我用的是maven依賴)
在官方的網(wǎng)站上也有的下載。 地址: http://jmock.org/dist/jmock-2.5.1-jars.zip
使用C2DM框架的要求
2. 使用C2DM功能的Android設(shè)備上需要設(shè)置好Google的賬戶。
3. C2DM需要依賴于Google官方提供的C2DM服務(wù)器,由于國內(nèi)的網(wǎng)絡(luò)環(huán)境,這個(gè)服務(wù)經(jīng)常不可用,如果想要很好的使用,我們的App Server必須也在國外,這個(gè)恐怕不是每個(gè)開發(fā)者都能夠?qū)崿F(xiàn)的

(2)C2DM服務(wù)器會(huì)返回一個(gè)registration_id值給Android設(shè)備,設(shè)備需要保存這個(gè)registration_id值。
(3)Android設(shè)備把獲得的registration_id和C2DM功能的用戶賬戶(android.c2dm.demo@gmail.com)發(fā)送給自己的服務(wù)器,不過一般用戶賬戶信息因?yàn)楹头?wù)器確定好的,所以不必發(fā)送。
這樣Android設(shè)備就完成了C2DM功能的注冊(cè)過程,接下來就可以接收C2DM服務(wù)器Push過來的消息了。
(4)服務(wù)器獲得數(shù)據(jù)。這里圖中的例子Chrome To Phone,服務(wù)器接收到Chrome瀏覽器發(fā)送的數(shù)據(jù)。數(shù)據(jù)也可以是服務(wù)器本地產(chǎn)生的。這里的服務(wù)器是Google AppEngine(很好的一項(xiàng)服務(wù),可惜在國內(nèi)被屏了),要換成自己的服務(wù)器。服務(wù)器還要獲取注冊(cè)使用C2DM功能的用戶賬戶(android.c2dm.demo@gmail.com)的ClientLogin權(quán)限Auth。
(5)服務(wù)器把要發(fā)送的數(shù)據(jù)和registration_id一起,并且頭部帶上獲取的Auth,使用POST的方式發(fā)送給C2DM服務(wù)器。
(6)C2DM服務(wù)器會(huì)以Push的方式把數(shù)據(jù)發(fā)送給對(duì)應(yīng)的Android設(shè)備,Android設(shè)備只要在程序中按之前和服務(wù)器商量好的格式從對(duì)應(yīng)的key中獲取數(shù)據(jù)即可。
轉(zhuǎn)自:
地理位置索引支持是MongoDB的一大亮點(diǎn),這也是全球最流行的LBS服務(wù)foursquare 選擇MongoDB的原因之一。我們知道,通常的數(shù)據(jù)庫索引結(jié)構(gòu)是B+ Tree,如何將地理位置轉(zhuǎn)化為可建立B+Tree的形式,下文將為你描述。
首先假設(shè)我們將需要索引的整個(gè)地圖分成16×16的方格,如下圖(左下角為坐標(biāo)0,0 右上角為坐標(biāo)16,16):
單純的[x,y]的數(shù)據(jù)是無法建立索引的,所以MongoDB在建立索引的時(shí)候,會(huì)根據(jù)相應(yīng)字段的坐標(biāo)計(jì)算一個(gè)可以用來做索引的hash值,這個(gè)值叫做geohash,下面我們以地圖上坐標(biāo)為[4,6]的點(diǎn)(圖中紅叉位置)為例。
我們第一步將整個(gè)地圖分成等大小的四塊,如下圖:
劃分成四塊后我們可以定義這四塊的值,如下(左下為00,左上為01,右下為10,右上為11):
01 | 11 |
00 | 10 |
這樣[4,6]點(diǎn)的geohash值目前為 00
然后再將四個(gè)小塊每一塊進(jìn)行切割,如下:
這時(shí)[4,6]點(diǎn)位于右上區(qū)域,右上的值為11,這樣[4,6]點(diǎn)的geohash值變?yōu)椋?011
繼續(xù)往下做兩次切分:
最終得到[4,6]點(diǎn)的geohash值為:00110100
這樣我們用這個(gè)值來做索引,則地圖上點(diǎn)相近的點(diǎn)就可以轉(zhuǎn)化成有相同前綴的geohash值了。
我們可以看到,這個(gè)geohash值的精確度是與劃分地圖的次數(shù)成正比的,上例對(duì)地圖劃分了四次。而MongoDB默認(rèn)是進(jìn)行26次劃分,這個(gè)值在建立索引時(shí)是可控的。具體建立二維地理位置索引的命令如下:
db.map.ensureIndex({point : "2d"}, {min : 0, max : 16, bits : 4})
其中的bits參數(shù)就是劃分幾次,默認(rèn)為26次。
http://terryblog.blog.51cto.com/1764499/547777
申請(qǐng)一個(gè)Android Maps API Key
需要輸入密碼:android
然后就會(huì)得到MD5的值,進(jìn)入
<HTML>
<HEAD>
<META http-equiv='Content-Type' content='text/html; charset=gb2312'>
<TITLE>可輸入的下拉框</TITLE>
</HEAD>
<BODY >
<div style="position:relative;">
<span style="margin-left:100px;width:18px;overflow:hidden;">
<select style="width:118px;margin-left:-100px" onchange="this.parentNode.nextSibling.value=this.value">
<option value="<option value="<option value="WEB開發(fā)者"> WEB開發(fā)者 </option>
</select></span><input name="box" style="width:100px;position:absolute;left:0px;">
</div>
</BODY></HTML>
單例創(chuàng)建模式是一個(gè)通用的編程習(xí)語。和多線程一起使用時(shí),必需使用某種類型的同步。在努力創(chuàng)建更有效的代碼時(shí),Java 程序員們創(chuàng)建了雙重檢查鎖定習(xí)語,將其和單例創(chuàng)建模式一起使用,從而限制同步代碼量。然而,由于一些不太常見的 Java 內(nèi)存模型細(xì)節(jié)的原因,并不能保證這個(gè)雙重檢查鎖定習(xí)語有效。它偶爾會(huì)失敗,而不是總失敗。此外,它失敗的原因并不明顯,還包含 Java 內(nèi)存模型的一些隱秘細(xì)節(jié)。這些事實(shí)將導(dǎo)致代碼失敗,原因是雙重檢查鎖定難于跟蹤。在本文余下的部分里,我們將詳細(xì)介紹雙重檢查鎖定習(xí)語,從而理解它在何處失效。
要理解雙重檢查鎖定習(xí)語是從哪里起源的,就必須理解通用單例創(chuàng)建習(xí)語,如清單 1 中的闡釋:
清單 1. 單例創(chuàng)建習(xí)語
import java.util.*; class Singleton { private static Singleton instance; private Vector v; private boolean inUse; private Singleton() { v = new Vector(); v.addElement(new Object()); inUse = true; } public static Singleton getInstance() { if (instance == null) //1 instance = new Singleton(); //2 return instance; //3 } } |
此類的設(shè)計(jì)確保只創(chuàng)建一個(gè) Singleton
對(duì)象。構(gòu)造函數(shù)被聲明為 private
,getInstance()
方法只創(chuàng)建一個(gè)對(duì)象。這個(gè)實(shí)現(xiàn)適合于單線程程序。然而,當(dāng)引入多線程時(shí),就必須通過同步來保護(hù) getInstance()
方法。如果不保護(hù) getInstance()
方法,則可能返回 Singleton
對(duì)象的兩個(gè)不同的實(shí)例。假設(shè)兩個(gè)線程并發(fā)調(diào)用 getInstance()
方法并且按以下順序執(zhí)行調(diào)用:
- 線程 1 調(diào)用
getInstance()
方法并決定instance
在 //1 處為null
。
- 線程 1 進(jìn)入
if
代碼塊,但在執(zhí)行 //2 處的代碼行時(shí)被線程 2 預(yù)占。
- 線程 2 調(diào)用
getInstance()
方法并在 //1 處決定instance
為null
。
- 線程 2 進(jìn)入
if
代碼塊并創(chuàng)建一個(gè)新的Singleton
對(duì)象并在 //2 處將變量instance
分配給這個(gè)新對(duì)象。
- 線程 2 在 //3 處返回
Singleton
對(duì)象引用。
- 線程 2 被線程 1 預(yù)占。
- 線程 1 在它停止的地方啟動(dòng),并執(zhí)行 //2 代碼行,這導(dǎo)致創(chuàng)建另一個(gè)
Singleton
對(duì)象。
- 線程 1 在 //3 處返回這個(gè)對(duì)象。
結(jié)果是 getInstance()
方法創(chuàng)建了兩個(gè) Singleton
對(duì)象,而它本該只創(chuàng)建一個(gè)對(duì)象。通過同步 getInstance()
方法從而在同一時(shí)間只允許一個(gè)線程執(zhí)行代碼,這個(gè)問題得以改正,如清單 2 所示:
清單 2. 線程安全的 getInstance() 方法
public static synchronized Singleton getInstance() { if (instance == null) //1 instance = new Singleton(); //2 return instance; //3 } |
清單 2 中的代碼針對(duì)多線程訪問 getInstance()
方法運(yùn)行得很好。然而,當(dāng)分析這段代碼時(shí),您會(huì)意識(shí)到只有在第一次調(diào)用方法時(shí)才需要同步。由于只有第一次調(diào)用執(zhí)行了 //2 處的代碼,而只有此行代碼需要同步,因此就無需對(duì)后續(xù)調(diào)用使用同步。所有其他調(diào)用用于決定 instance
是非 null
的,并將其返回。多線程能夠安全并發(fā)地執(zhí)行除第一次調(diào)用外的所有調(diào)用。盡管如此,由于該方法是 synchronized
的,需要為該方法的每一次調(diào)用付出同步的代價(jià),即使只有第一次調(diào)用需要同步。
為使此方法更為有效,一個(gè)被稱為雙重檢查鎖定的習(xí)語就應(yīng)運(yùn)而生了。這個(gè)想法是為了避免對(duì)除第一次調(diào)用外的所有調(diào)用都實(shí)行同步的昂貴代價(jià)。同步的代價(jià)在不同的 JVM 間是不同的。在早期,代價(jià)相當(dāng)高。隨著更高級(jí)的 JVM 的出現(xiàn),同步的代價(jià)降低了,但出入 synchronized
方法或塊仍然有性能損失。不考慮 JVM 技術(shù)的進(jìn)步,程序員們絕不想不必要地浪費(fèi)處理時(shí)間。
因?yàn)橹挥星鍐?2 中的 //2 行需要同步,我們可以只將其包裝到一個(gè)同步塊中,如清單 3 所示:
清單 3. getInstance() 方法
public static Singleton getInstance() { if (instance == null) { synchronized(Singleton.class) { instance = new Singleton(); } } return instance; } |
清單 3 中的代碼展示了用多線程加以說明的和清單 1 相同的問題。當(dāng) instance
為 null
時(shí),兩個(gè)線程可以并發(fā)地進(jìn)入 if
語句內(nèi)部。然后,一個(gè)線程進(jìn)入 synchronized
塊來初始化 instance
,而另一個(gè)線程則被阻斷。當(dāng)?shù)谝粋€(gè)線程退出 synchronized
塊時(shí),等待著的線程進(jìn)入并創(chuàng)建另一個(gè) Singleton
對(duì)象。注意:當(dāng)?shù)诙€(gè)線程進(jìn)入 synchronized
塊時(shí),它并沒有檢查 instance
是否非 null
。
![]() ![]() |
![]()
|
為處理清單 3 中的問題,我們需要對(duì) instance
進(jìn)行第二次檢查。這就是“雙重檢查鎖定”名稱的由來。將雙重檢查鎖定習(xí)語應(yīng)用到清單 3 的結(jié)果就是清單 4 。
清單 4. 雙重檢查鎖定示例
public static Singleton getInstance() { if (instance == null) { synchronized(Singleton.class) { //1 if (instance == null) //2 instance = new Singleton(); //3 } } return instance; } |
雙重檢查鎖定背后的理論是:在 //2 處的第二次檢查使(如清單 3 中那樣)創(chuàng)建兩個(gè)不同的 Singleton
對(duì)象成為不可能。假設(shè)有下列事件序列:
- 線程 1 進(jìn)入
getInstance()
方法。
- 由于
instance
為null
,線程 1 在 //1 處進(jìn)入synchronized
塊。
- 線程 1 被線程 2 預(yù)占。
- 線程 2 進(jìn)入
getInstance()
方法。
- 由于
instance
仍舊為null
,線程 2 試圖獲取 //1 處的鎖。然而,由于線程 1 持有該鎖,線程 2 在 //1 處阻塞。
- 線程 2 被線程 1 預(yù)占。
- 線程 1 執(zhí)行,由于在 //2 處實(shí)例仍舊為
null
,線程 1 還創(chuàng)建一個(gè)Singleton
對(duì)象并將其引用賦值給instance
。
- 線程 1 退出
synchronized
塊并從getInstance()
方法返回實(shí)例。
- 線程 1 被線程 2 預(yù)占。
- 線程 2 獲取 //1 處的鎖并檢查
instance
是否為null
。
- 由于
instance
是非null
的,并沒有創(chuàng)建第二個(gè)Singleton
對(duì)象,由線程 1 創(chuàng)建的對(duì)象被返回。
雙重檢查鎖定背后的理論是完美的。不幸地是,現(xiàn)實(shí)完全不同。雙重檢查鎖定的問題是:并不能保證它會(huì)在單處理器或多處理器計(jì)算機(jī)上順利運(yùn)行。
雙重檢查鎖定失敗的問題并不歸咎于 JVM 中的實(shí)現(xiàn) bug,而是歸咎于 Java 平臺(tái)內(nèi)存模型。內(nèi)存模型允許所謂的“無序?qū)懭?#8221;,這也是這些習(xí)語失敗的一個(gè)主要原因。
![]() ![]() |
![]()
|
為解釋該問題,需要重新考察上述清單 4 中的 //3 行。此行代碼創(chuàng)建了一個(gè) Singleton
對(duì)象并初始化變量 instance
來引用此對(duì)象。這行代碼的問題是:在 Singleton
構(gòu)造函數(shù)體執(zhí)行之前,變量 instance
可能成為非 null
的。
什么?這一說法可能讓您始料未及,但事實(shí)確實(shí)如此。在解釋這個(gè)現(xiàn)象如何發(fā)生前,請(qǐng)先暫時(shí)接受這一事實(shí),我們先來考察一下雙重檢查鎖定是如何被破壞的。假設(shè)清單 4 中代碼執(zhí)行以下事件序列:
- 線程 1 進(jìn)入
getInstance()
方法。
- 由于
instance
為null
,線程 1 在 //1 處進(jìn)入synchronized
塊。
- 線程 1 前進(jìn)到 //3 處,但在構(gòu)造函數(shù)執(zhí)行之前,使實(shí)例成為非
null
。
- 線程 1 被線程 2 預(yù)占。
- 線程 2 檢查實(shí)例是否為
null
。因?yàn)閷?shí)例不為 null,線程 2 將instance
引用返回給一個(gè)構(gòu)造完整但部分初始化了的Singleton
對(duì)象。
- 線程 2 被線程 1 預(yù)占。
- 線程 1 通過運(yùn)行
Singleton
對(duì)象的構(gòu)造函數(shù)并將引用返回給它,來完成對(duì)該對(duì)象的初始化。
此事件序列發(fā)生在線程 2 返回一個(gè)尚未執(zhí)行構(gòu)造函數(shù)的對(duì)象的時(shí)候。
為展示此事件的發(fā)生情況,假設(shè)為代碼行 instance =new Singleton();
執(zhí)行了下列偽代碼: instance =new Singleton();
mem = allocate(); //Allocate memory for Singleton object. instance = mem; //Note that instance is now non-null, but //has not been initialized. ctorSingleton(instance); //Invoke constructor for Singleton passing //instance. |
這段偽代碼不僅是可能的,而且是一些 JIT 編譯器上真實(shí)發(fā)生的。執(zhí)行的順序是顛倒的,但鑒于當(dāng)前的內(nèi)存模型,這也是允許發(fā)生的。JIT 編譯器的這一行為使雙重檢查鎖定的問題只不過是一次學(xué)術(shù)實(shí)踐而已。
為說明這一情況,假設(shè)有清單 5 中的代碼。它包含一個(gè)剝離版的 getInstance()
方法。我已經(jīng)刪除了“雙重檢查性”以簡(jiǎn)化我們對(duì)生成的匯編代碼(清單 6)的回顧。我們只關(guān)心 JIT 編譯器如何編譯 instance=new Singleton();
代碼。此外,我提供了一個(gè)簡(jiǎn)單的構(gòu)造函數(shù)來明確說明匯編代碼中該構(gòu)造函數(shù)的運(yùn)行情況。
清單 5. 用于演示無序?qū)懭氲膯卫?/strong>
class Singleton { private static Singleton instance; private boolean inUse; private int val; private Singleton() { inUse = true; val = 5; } public static Singleton getInstance() { if (instance == null) instance = new Singleton(); return instance; } } |
清單 6 包含由 Sun JDK 1.2.1 JIT 編譯器為清單 5 中的 getInstance()
方法體生成的匯編代碼。
清單 6. 由清單 5 中的代碼生成的匯編代碼
;asm code generated for getInstance 054D20B0 mov eax,[049388C8] ;load instance ref 054D20B5 test eax,eax ;test for null 054D20B7 jne 054D20D7 054D20B9 mov eax,14C0988h 054D20BE call 503EF8F0 ;allocate memory 054D20C3 mov [049388C8],eax ;store pointer in ;instance ref. instance ;non-null and ctor ;has not run 054D20C8 mov ecx,dword ptr [eax] 054D20CA mov dword ptr [ecx],1 ;inline ctor - inUse=true; 054D20D0 mov dword ptr [ecx+4],5 ;inline ctor - val=5; 054D20D7 mov ebx,dword ptr ds:[49388C8h] 054D20DD jmp 054D20B0 |
注: 為引用下列說明中的匯編代碼行,我將引用指令地址的最后兩個(gè)值,因?yàn)樗鼈兌家?054D20
開頭。例如,B5
代表 test eax,eax
。
匯編代碼是通過運(yùn)行一個(gè)在無限循環(huán)中調(diào)用 getInstance()
方法的測(cè)試程序來生成的。程序運(yùn)行時(shí),請(qǐng)運(yùn)行 Microsoft Visual C++ 調(diào)試器并將其附到表示測(cè)試程序的 Java 進(jìn)程中。然后,中斷執(zhí)行并找到表示該無限循環(huán)的匯編代碼。
B0
和 B5
處的前兩行匯編代碼將 instance
引用從內(nèi)存位置 049388C8
加載至 eax
中,并進(jìn)行 null
檢查。這跟清單 5 中的 getInstance()
方法的第一行代碼相對(duì)應(yīng)。第一次調(diào)用此方法時(shí),instance
為 null
,代碼執(zhí)行到 B9
。BE
處的代碼為 Singleton
對(duì)象從堆中分配內(nèi)存,并將一個(gè)指向該塊內(nèi)存的指針存儲(chǔ)到 eax
中。下一行代碼,C3
,獲取 eax
中的指針并將其存儲(chǔ)回內(nèi)存位置為 049388C8
的實(shí)例引用。結(jié)果是,instance
現(xiàn)在為非 null
并引用一個(gè)有效的 Singleton
對(duì)象。然而,此對(duì)象的構(gòu)造函數(shù)尚未運(yùn)行,這恰是破壞雙重檢查鎖定的情況。然后,在 C8
行處,instance
指針被解除引用并存儲(chǔ)到 ecx
。CA
和 D0
行表示內(nèi)聯(lián)的構(gòu)造函數(shù),該構(gòu)造函數(shù)將值 true
和 5
存儲(chǔ)到 Singleton
對(duì)象。如果此代碼在執(zhí)行 C3
行后且在完成該構(gòu)造函數(shù)前被另一個(gè)線程中斷,則雙重檢查鎖定就會(huì)失敗。
不是所有的 JIT 編譯器都生成如上代碼。一些生成了代碼,從而只在構(gòu)造函數(shù)執(zhí)行后使 instance
成為非 null
。針對(duì) Java 技術(shù)的 IBM SDK 1.3 版和 Sun JDK 1.3 都生成這樣的代碼。然而,這并不意味著應(yīng)該在這些實(shí)例中使用雙重檢查鎖定。該習(xí)語失敗還有一些其他原因。此外,您并不總能知道代碼會(huì)在哪些 JVM 上運(yùn)行,而 JIT 編譯器總是會(huì)發(fā)生變化,從而生成破壞此習(xí)語的代碼。
![]() ![]() |
![]()
|
考慮到當(dāng)前的雙重檢查鎖定不起作用,我加入了另一個(gè)版本的代碼,如清單 7 所示,從而防止您剛才看到的無序?qū)懭雴栴}。
清單 7. 解決無序?qū)懭雴栴}的嘗試
public static Singleton getInstance() { if (instance == null) { synchronized(Singleton.class) { //1 Singleton inst = instance; //2 if (inst == null) { synchronized(Singleton.class) { //3 inst = new Singleton(); //4 } instance = inst; //5 } } } return instance; } |
看著清單 7 中的代碼,您應(yīng)該意識(shí)到事情變得有點(diǎn)荒謬。請(qǐng)記住,創(chuàng)建雙重檢查鎖定是為了避免對(duì)簡(jiǎn)單的三行 getInstance()
方法實(shí)現(xiàn)同步。清單 7 中的代碼變得難于控制。另外,該代碼沒有解決問題。仔細(xì)檢查可獲悉原因。
此代碼試圖避免無序?qū)懭雴栴}。它試圖通過引入局部變量 inst
和第二個(gè) synchronized
塊來解決這一問題。該理論實(shí)現(xiàn)如下:
- 線程 1 進(jìn)入
getInstance()
方法。
- 由于
instance
為null
,線程 1 在 //1 處進(jìn)入第一個(gè)synchronized
塊。
- 局部變量
inst
獲取instance
的值,該值在 //2 處為null
。
- 由于
inst
為null
,線程 1 在 //3 處進(jìn)入第二個(gè)synchronized
塊。
- 線程 1 然后開始執(zhí)行 //4 處的代碼,同時(shí)使
inst
為非null
,但在Singleton
的構(gòu)造函數(shù)執(zhí)行前。(這就是我們剛才看到的無序?qū)懭雴栴}。)
- 線程 1 被線程 2 預(yù)占。
- 線程 2 進(jìn)入
getInstance()
方法。
- 由于
instance
為null
,線程 2 試圖在 //1 處進(jìn)入第一個(gè)synchronized
塊。由于線程 1 目前持有此鎖,線程 2 被阻斷。
- 線程 1 然后完成 //4 處的執(zhí)行。
- 線程 1 然后將一個(gè)構(gòu)造完整的
Singleton
對(duì)象在 //5 處賦值給變量instance
,并退出這兩個(gè)synchronized
塊。
- 線程 1 返回
instance
。
- 然后執(zhí)行線程 2 并在 //2 處將
instance
賦值給inst
。
- 線程 2 發(fā)現(xiàn)
instance
為非null
,將其返回。
這里的關(guān)鍵行是 //5。此行應(yīng)該確保 instance
只為 null
或引用一個(gè)構(gòu)造完整的 Singleton
對(duì)象。該問題發(fā)生在理論和實(shí)際彼此背道而馳的情況下。
由于當(dāng)前內(nèi)存模型的定義,清單 7 中的代碼無效。Java 語言規(guī)范(Java Language Specification,JLS)要求不能將 synchronized
塊中的代碼移出來。但是,并沒有說不能將 synchronized
塊外面的代碼移入 synchronized
塊中。
JIT 編譯器會(huì)在這里看到一個(gè)優(yōu)化的機(jī)會(huì)。此優(yōu)化會(huì)刪除 //4 和 //5 處的代碼,組合并且生成清單 8 中所示的代碼。
清單 8. 從清單 7 中優(yōu)化來的代碼。
public static Singleton getInstance() { if (instance == null) { synchronized(Singleton.class) { //1 Singleton inst = instance; //2 if (inst == null) { synchronized(Singleton.class) { //3 //inst = new Singleton(); //4 instance = new Singleton(); } //instance = inst; //5 } } } return instance; } |
如果進(jìn)行此項(xiàng)優(yōu)化,您將同樣遇到我們之前討論過的無序?qū)懭雴栴}。
![]() ![]() |
![]()
|
另一個(gè)想法是針對(duì)變量 inst
以及 instance
使用關(guān)鍵字 volatile
。根據(jù) JLS(參見 參考資料),聲明成 volatile
的變量被認(rèn)為是順序一致的,即,不是重新排序的。但是試圖使用 volatile
來修正雙重檢查鎖定的問題,會(huì)產(chǎn)生以下兩個(gè)問題:
- 這里的問題不是有關(guān)順序一致性的,而是代碼被移動(dòng)了,不是重新排序。
- 即使考慮了順序一致性,大多數(shù)的 JVM 也沒有正確地實(shí)現(xiàn)
volatile
。
第二點(diǎn)值得展開討論。假設(shè)有清單 9 中的代碼:
清單 9. 使用了 volatile 的順序一致性
class test { private volatile boolean stop = false; private volatile int num = 0; public void foo() { num = 100; //This can happen second stop = true; //This can happen first //... } public void bar() { if (stop) num += num; //num can == 0! } //... } |
根據(jù) JLS,由于 stop
和 num
被聲明為 volatile
,它們應(yīng)該順序一致。這意味著如果 stop
曾經(jīng)是 true
,num
一定曾被設(shè)置成 100
。盡管如此,因?yàn)樵S多 JVM 沒有實(shí)現(xiàn) volatile
的順序一致性功能,您就不能依賴此行為。因此,如果線程 1 調(diào)用 foo
并且線程 2 并發(fā)地調(diào)用 bar
,則線程 1 可能在 num
被設(shè)置成為 100
之前將 stop
設(shè)置成 true
。這將導(dǎo)致線程見到 stop
是 true
,而 num
仍被設(shè)置成 0
。使用 volatile
和 64 位變量的原子數(shù)還有另外一些問題,但這已超出了本文的討論范圍。有關(guān)此主題的更多信息,請(qǐng)參閱 參考資料。
![]() ![]() |
![]()
|
底線就是:無論以何種形式,都不應(yīng)使用雙重檢查鎖定,因?yàn)槟荒鼙WC它在任何 JVM 實(shí)現(xiàn)上都能順利運(yùn)行。JSR-133 是有關(guān)內(nèi)存模型尋址問題的,盡管如此,新的內(nèi)存模型也不會(huì)支持雙重檢查鎖定。因此,您有兩種選擇:
- 接受如清單 2 中所示的
getInstance()
方法的同步。
- 放棄同步,而使用一個(gè)
static
字段。
選擇項(xiàng) 2 如清單 10 中所示
清單 10. 使用 static 字段的單例實(shí)現(xiàn)
class Singleton { private Vector v; private boolean inUse; private static Singleton instance = new Singleton(); private Singleton() { v = new Vector(); inUse = true; //... } public static Singleton getInstance() { return instance; } } |
清單 10 的代碼沒有使用同步,并且確保調(diào)用 static getInstance()
方法時(shí)才創(chuàng)建 Singleton
。如果您的目標(biāo)是消除同步,則這將是一個(gè)很好的選擇。
![]() ![]() |
![]()
|
鑒于無序?qū)懭牒鸵迷跇?gòu)造函數(shù)執(zhí)行前變成非 null
的問題,您可能會(huì)考慮 String
類。假設(shè)有下列代碼:
private String str; //... str = new String("hello"); |
String
類應(yīng)該是不變的。盡管如此,鑒于我們之前討論的無序?qū)懭雴栴},那會(huì)在這里導(dǎo)致問題嗎?答案是肯定的。考慮兩個(gè)線程訪問 String str
。一個(gè)線程能看見 str
引用一個(gè) String
對(duì)象,在該對(duì)象中構(gòu)造函數(shù)尚未運(yùn)行。事實(shí)上,清單 11 包含展示這種情況發(fā)生的代碼。注意,這個(gè)代碼僅在我測(cè)試用的舊版 JVM 上會(huì)失敗。IBM 1.3 和 Sun 1.3 JVM 都會(huì)如期生成不變的 String
。
清單 11. 可變 String 的例子
class StringCreator extends Thread { MutableString ms; public StringCreator(MutableString muts) { ms = muts; } public void run() { while(true) ms.str = new String("hello"); //1 } } class StringReader extends Thread { MutableString ms; public StringReader(MutableString muts) { ms = muts; } public void run() { while(true) { if (!(ms.str.equals("hello"))) //2 { System.out.println("String is not immutable!"); break; } } } } class MutableString { public String str; //3 public static void main(String args[]) { MutableString ms = new MutableString(); //4 new StringCreator(ms).start(); //5 new StringReader(ms).start(); //6 } } |
此代碼在 //4 處創(chuàng)建一個(gè) MutableString
類,它包含了一個(gè) String
引用,此引用由 //3 處的兩個(gè)線程共享。在行 //5 和 //6 處,在兩個(gè)分開的線程上創(chuàng)建了兩個(gè)對(duì)象 StringCreator
和 StringReader
。傳入一個(gè) MutableString
對(duì)象的引用。StringCreator
類進(jìn)入到一個(gè)無限循環(huán)中并且使用值“hello”在 //1 處創(chuàng)建 String
對(duì)象。StringReader
也進(jìn)入到一個(gè)無限循環(huán)中,并且在 //2 處檢查當(dāng)前的 String
對(duì)象的值是不是 “hello”。如果不行,StringReader
線程打印出一條消息并停止。如果 String
類是不變的,則從此程序應(yīng)當(dāng)看不到任何輸出。如果發(fā)生了無序?qū)懭雴栴},則使 StringReader
看到 str
引用的惟一方法絕不是值為“hello”的 String
對(duì)象。
在舊版的 JVM 如 Sun JDK 1.2.1 上運(yùn)行此代碼會(huì)導(dǎo)致無序?qū)懭雴栴}。并因此導(dǎo)致一個(gè)非不變的 String
。
![]() ![]() |
![]()
|
為避免單例中代價(jià)高昂的同步,程序員非常聰明地發(fā)明了雙重檢查鎖定習(xí)語。不幸的是,鑒于當(dāng)前的內(nèi)存模型的原因,該習(xí)語尚未得到廣泛使用,就明顯成為了一種不安全的編程結(jié)構(gòu)。重定義脆弱的內(nèi)存模型這一領(lǐng)域的工作正在進(jìn)行中。盡管如此,即使是在新提議的內(nèi)存模型中,雙重檢查鎖定也是無效的。對(duì)此問題最佳的解決方案是接受同步或者使用一個(gè) static field
。
工薪族月薪2000元的理財(cái)竅門
在有很多的大學(xué)生都是在畢業(yè)以后選擇留在自己上學(xué)的城市,一來對(duì)城市有了感情,二來也希望能在大的城市有所發(fā)展,而現(xiàn)在很多大城市勞動(dòng)力過剩,大學(xué)生想找到一個(gè)自己喜歡又有較高收入的職位已經(jīng)變得非常難,很多剛畢業(yè)的朋友的月收入都可能徘徊在2000元人民幣左右,如果您是這樣的情況,讓我們來核算一下,如何利用手中的有限資金來進(jìn)行理財(cái)。如果您是單身一人,月收入在2000人民幣,又沒有其他的獎(jiǎng)金分紅等收入,那年收入就固定在25000元左右。如何來支配這些錢呢?
生活費(fèi)占收入30%-40%
首先,你要拿出每個(gè)月必須支付的生活費(fèi)。如房租、水電、通訊費(fèi)、柴米油鹽等,這部分約占收入三分之一。它們是你生活中不可或缺的部分,滿足你最基本的物質(zhì)需求。離開了它們,你就會(huì)像魚兒離開了水一樣無法生活,所以無論如何,請(qǐng)你先從收入中抽出這部分,不要?jiǎng)佑谩?br /> 儲(chǔ)蓄占收入10%-20%
其次,是自己用來儲(chǔ)蓄的部分,約占收入的10%-20%。很多人每次也都會(huì)在月初存錢,但是到了月底的時(shí)候,往往就變成了泡沫,存進(jìn)去的大部分又取出來了,而且是不知不覺的,好像憑空消失了一樣,總是在自己喜歡的衣飾、雜志、CD或朋友聚會(huì)上不加以節(jié)制。你要自己提醒自己,起碼,你的存儲(chǔ)能保證你3個(gè)月的基本生活。要知道,現(xiàn)在很多公司動(dòng)輒減薪裁員。如果你一點(diǎn)儲(chǔ)蓄都沒有,一旦工作發(fā)生了變動(dòng),你將會(huì)非常被動(dòng)。
而且這3個(gè)月的收入可以成為你的定心丸,工作實(shí)在干得不開心了,忍無可忍無需再忍時(shí),你可以瀟灑地對(duì)老板說聲“拜拜”。想想可以不用受你不喜歡的工作和人的氣,是多么開心的事啊。所以,無論如何,請(qǐng)為自己留條退路。
活動(dòng)資金占收入30%~40%
剩下的這部分錢,約占收入的三分之一。可以根據(jù)自己當(dāng)時(shí)的生活目標(biāo),側(cè)重地花在不同的地方。譬如“五一”、“十一”可以安排旅游;服裝打折時(shí)可以購進(jìn)自己心儀已久的牌子貨;還有平時(shí)必不可少的購買CD、朋友聚會(huì)的開銷。這樣花起來心里有數(shù),不會(huì)一下子把錢都用完。
最關(guān)鍵的是,即使一發(fā)薪水就把這部分用完了,也可當(dāng)是一次教訓(xùn),可以懲罰自己一個(gè)月內(nèi)什么都不能再干了(就當(dāng)是收入全部支出了吧),印象會(huì)很深刻而且有效。
除去吃、穿、住、行以及其他的消費(fèi)外,再怎么節(jié)省,估計(jì)您現(xiàn)在的狀況,一年也只有10000元的積蓄,想來這些都是剛畢業(yè)的絕大部分學(xué)生所面臨的實(shí)際情況。如何讓錢生錢是大家想得最多的事情,然而,畢竟收入有限,很多想法都不容易實(shí)現(xiàn),建議處于這個(gè)階段的朋友,最重要的是開源,節(jié)流只是我們生活工作的一部分,就像大廈的基層一樣。而最重要的是怎樣財(cái)源滾滾、開源有道,為了達(dá)到一個(gè)新目標(biāo),你必須不斷進(jìn)步以求發(fā)展,培養(yǎng)自己的實(shí)力以求進(jìn)步,這才是真正的生財(cái)之道。可以安心地發(fā)展自己的事業(yè),積累自己的經(jīng)驗(yàn),充實(shí)自己,使自己不斷地提高,才會(huì)有好的發(fā)展,要相信“機(jī)會(huì)總是給有準(zhǔn)備的人”。
當(dāng)然,既然有了些許積蓄,也不能讓它閑置,我們建議把1萬元分為5份,分成5個(gè)2000元,分別作出適當(dāng)?shù)耐顿Y安排。這樣,家庭不會(huì)出現(xiàn)用錢危機(jī),并可以獲得最大的收益。
(1)用2000元買國債,這是回報(bào)率較高而又很保險(xiǎn)的一種投資。
(2)用2000元買保險(xiǎn)。以往人們的保險(xiǎn)意識(shí)很淡薄,實(shí)際上購買保險(xiǎn)也是一種較好的投資方式,而且保險(xiǎn)金不在利息稅征收之列。尤其是各壽險(xiǎn)公司都推出了兩全型險(xiǎn)種,增加了有關(guān)“權(quán)益轉(zhuǎn)換”的條款,即一旦銀行利率上升,客戶可在保險(xiǎn)公司出售的險(xiǎn)種中進(jìn)行轉(zhuǎn)換,并獲得保險(xiǎn)公司給予的一定的價(jià)格折扣、免予核保等優(yōu)惠政策。
(3)用2000元買股票。這是一種風(fēng)險(xiǎn)最大的投資,當(dāng)然風(fēng)險(xiǎn)與收益是并存的,只要選擇得當(dāng),會(huì)帶來理想的投資回報(bào)。除股票外,期貨、投資債券等都屬這一類。不過,參與這類投資,要求有相應(yīng)的行業(yè)知識(shí)和較強(qiáng)的風(fēng)險(xiǎn)意識(shí)。
(4)用2000元存定期存款,這是一種幾乎沒有風(fēng)險(xiǎn)的投資方式,也是未來對(duì)家庭生活的一種保障。
(5)用2000元存活期存款,這是為了應(yīng)急之用。如家里臨時(shí)急需用錢,有一定數(shù)量的活期儲(chǔ)蓄存款可解燃眉之急,而且存取又很方便。
這種方法是許多人經(jīng)過多年嘗試后總結(jié)出的一套成功的理財(cái)經(jīng)驗(yàn)。當(dāng)然,各個(gè)家庭可以根據(jù)不同情況,靈活使用。
正確理財(cái)三個(gè)觀念
建立理財(cái)觀念一:理財(cái)是一件正大光明的事,“你不理財(cái),財(cái)不理你”。
建立理財(cái)觀念二:理財(cái)要從現(xiàn)在開始,并長期堅(jiān)持。
建立理財(cái)觀念三:理財(cái)目的是“梳理財(cái)富,增值生活”。
理財(cái)四個(gè)誤區(qū)
理財(cái)觀念誤區(qū)一:我沒財(cái)可理;
理財(cái)觀念誤區(qū)二:我不需要理財(cái);
理財(cái)觀念誤區(qū)三:等我有了錢再理財(cái);
理財(cái)觀念誤區(qū)四:會(huì)理財(cái)不如會(huì)掙錢。
理財(cái)?shù)奈宕竽繕?biāo)
目標(biāo)一:獲得資產(chǎn)增值;
目標(biāo)二:保證資金安全;
目標(biāo)三:防御意外事故;
目標(biāo)四:保證老有所養(yǎng);
目標(biāo)五:提供贍養(yǎng)父母及撫養(yǎng)教育子女的基金。
--------------------精彩閱讀推薦--------------------
【500強(qiáng)企業(yè)的薪水有多高?】
全球500強(qiáng)大企業(yè)的薪水實(shí)情大揭密
不一定要是自己的offer letter上的數(shù)據(jù),凡是能夠確認(rèn)比較準(zhǔn)確的公司薪水都可補(bǔ)充。補(bǔ)充的話最好說明職位、本碩區(qū)別、多少個(gè)月工資、獎(jiǎng)金。寶潔:本7200、研8200、博9700,均14個(gè)月,另有交通補(bǔ)助,區(qū)域補(bǔ)助等,CBD,marketing每幾個(gè)月漲20%-30%不定。
【工薪族的你跑贏通脹了嗎?】
工薪族理財(cái)跑贏通脹 開源節(jié)流資產(chǎn)合理配備
龍先生家是典型的工薪階層。龍先生47歲,是某大型企業(yè)的技術(shù)師,年收入5.5萬元,購買了各類基本保險(xiǎn)。太太42歲,是某商場(chǎng)的合同工,年收入4萬元,購買了基本的社會(huì)保險(xiǎn)。兩人均在單位吃中午飯,搭班車上下班。兒子16歲,尚在讀高中。
【怎樣才能錢生錢?】
“階梯存儲(chǔ)”應(yīng)對(duì)利率調(diào)整 學(xué)三招輕松錢生錢
當(dāng)前,儲(chǔ)蓄依然在居民理財(cái)?shù)耐顿Y組合中占據(jù)著重要地位,但在當(dāng)前的加息周期內(nèi),一些人因缺乏科學(xué)的儲(chǔ)蓄理財(cái)規(guī)劃而損失利息收入。理財(cái)專家建議,進(jìn)入加息周期,為了使儲(chǔ)蓄理財(cái)能賺取更多的利息收入,儲(chǔ)戶應(yīng)在存款期限、存款金額和存款方式上注意以下幾點(diǎn)。
【爺們的臉往哪擱!】
女人太會(huì)賺錢也是錯(cuò)? 爺們兒的臉往哪擱
女人財(cái)大就氣粗?別偏激,妻子賺錢自己也是受益者,所以首先心態(tài)放平和些,別太執(zhí)著于傳統(tǒng)的思維和他人的看法。會(huì)不會(huì)賺錢是女人衡量男人的重要標(biāo)尺。男人沒錢,女人覺得沒有面子,不愿提及她的男人;有錢男人不怕提及他女人,無論漂亮與否,只要不給他戴綠帽子。
說起精致,最容易想起的詞大概是瓷器了,但這個(gè)詞用到程序員身上,肯定讓很多人覺得摸不著頭腦,在詳述"精致"這個(gè)詞以前,還是先來看一個(gè)"破窗理論",讓我們真正的理解"精致"的概念。
最早的"破窗理論",也稱"破窗謬論",源自于一位經(jīng)濟(jì)學(xué)家黑茲利特(也有人說源于法國19世紀(jì)經(jīng)濟(jì)學(xué)家巴斯夏),用來指出"破壞創(chuàng)造財(cái)富"的概念,以徹底地否定凱恩斯主義的政府干預(yù)政策。但后來美國斯坦福大學(xué)心理學(xué)家詹巴斗和犯罪學(xué)家凱琳也提出了相應(yīng)的"破窗理論"。
心理學(xué)家詹巴斗進(jìn)行了一項(xiàng)試驗(yàn),他把兩輛一模一樣的汽車分別停放在帕羅阿爾托的中產(chǎn)階級(jí)社區(qū)和相對(duì)雜亂的布朗克斯街區(qū)。對(duì)停在布朗克斯街區(qū)的那一輛,他摘掉了車牌,并且把頂棚打開,結(jié)果不到一天就被人偷走了;而停放在帕羅阿爾托的那一輛,停了一個(gè)星期也無人問津。后來,詹巴斗用錘子把這輛車的玻璃敲了個(gè)大洞,結(jié)果僅僅過了幾個(gè)小時(shí)車就不見了。
而犯罪學(xué)家凱琳曾注意到一個(gè)問題:在她上班的路旁,有一座非常漂亮的大樓,有一天,她注意到樓上有一窗子的玻璃被打破了,那扇破窗與整座大樓的整潔美麗極不調(diào)諧,顯得格外的刺眼。又過了一段時(shí)間,她驚奇地發(fā)現(xiàn):那扇破窗不但沒得到及時(shí)的維修,反而又增加了幾個(gè)帶爛玻璃的窗子……這一發(fā)現(xiàn)使她的心中忽有所悟:如果有人打壞了一個(gè)建筑物的窗戶玻璃,而這扇窗戶又得不到及時(shí)維修的話,別人就可能受到某些暗示性的縱容去打爛更多的玻璃。久而久之,這些破窗戶就給人造成一種無序的感覺;其結(jié)果是:在這種麻木不仁的氛圍中,犯罪就會(huì)滋生。這就是凱琳著名的"破窗理論"。
后來的"破窗理論",已經(jīng)突破原有經(jīng)濟(jì)學(xué)上的概念,有了新的意義:殘缺不全的東西更容易遭受到別人的破壞。前面的汽車和窗戶都表明了這一點(diǎn)。
其實(shí)作為程序員開發(fā)軟件也是一樣,可能有十種好的方法去寫一個(gè)功能,一個(gè)類,但同時(shí)可能會(huì)有一百種更快捷但不好的方法去做同樣的事情,很多程序員會(huì)因?yàn)楦鞣N原因,如時(shí)間壓力,工作強(qiáng)度,技術(shù)水平等一系列問題選擇了后者而非前者。同樣的事情還發(fā)生在維護(hù)和修改階段,當(dāng)看到別人的代碼寫的隨意,不好時(shí),那么自然就會(huì)沿著別人的方向走下去,結(jié)果就是產(chǎn)生出更多不好的代碼,這是在代碼開發(fā)中的一個(gè)典型"破窗理論"的體現(xiàn)。
承認(rèn)一點(diǎn),現(xiàn)實(shí)世界是不完美,特別是開發(fā)中,因?yàn)闀r(shí)間,精力,能力等各種因素,我們始終是要打破一些窗戶,但是卻要記住兩點(diǎn):
1.一個(gè)月前多打破了一扇窗戶,結(jié)果一個(gè)月就會(huì)打破10 扇甚至更多的窗戶。
2.如果打破了一扇窗戶,就要記住,遲早應(yīng)該將它補(bǔ)上。
因?yàn)楦鞣矫娴脑颍粋€(gè)程序員也許不能做到精致的代碼,但是如果一個(gè)程序員不想去做精致的代碼,那么又何必選擇軟件開發(fā)呢?
最近有Java解壓縮的需求,java.util.zip實(shí)在不好用,對(duì)中文支持也不行。所以選擇了強(qiáng)大的TrueZIP,使用時(shí)遇到了一個(gè)問題,做個(gè)記錄。
解壓縮代碼如下:
ArchiveDetector detector = new DefaultArchiveDetector(ArchiveDetector.ALL,
new Object[] { "zip", new CheckedZip32Driver("GBK") } );
File zipFile = new File("zipFile", detector);
File dst = new File("dst");
// 解壓縮
zipFile.copyAllTo(dst);
代碼十分簡(jiǎn)潔,注意這個(gè)File是
de.schlichtherle.io.File
不是
java.io.File
當(dāng)處理完業(yè)務(wù)要?jiǎng)h除這個(gè)Zip File時(shí),問題出現(xiàn)了:
這個(gè)文件刪不掉!!!
把自己的代碼檢查了好久,確認(rèn)沒問題后,開始從TrueZIP下手,發(fā)現(xiàn)它有特殊的地方的,是提示過的:
File file = new File(“archive.zip”); // de.schlichtherle.io.File!
Please do not do this instead:
de.schlichtherle.io.File file = new de.schlichtherle.io.File(“archive.zip”);
This is for the following reasons:
1.Accidentally using java.io.File and de.schlichtherle.io.File instances referring to the same path concurrently will result in erroneous behaviour and may even cause loss of data! Please refer to the section “Third Party Access” in the package Javadoc of de.schlichtherle.io for for full details and workarounds.
2.A de.schlichtherle.io.File subclasses java.io.File and thanks to polymorphism can be used everywhere a java.io.File could be used.
原來兩個(gè)File不能交叉使用,搞清楚原因了,加這么一句代碼搞定。
zipFile.deleteAll();
antlr簡(jiǎn)介
目前的ANTLR支持的語法層的選項(xiàng)主要包括:
語言選項(xiàng)(Language)、
輸出選項(xiàng)(output)、
回溯選項(xiàng)(backtrack)、
記憶選項(xiàng) (memorize)、
記號(hào)詞庫(tokenVocab)、
重寫選項(xiàng)(rewrite)、
超類選項(xiàng)(superClass)、
過濾選項(xiàng)(Filter)、
AST標(biāo)簽類型(ASTLabelType)
K選項(xiàng)
/**
//一些寫法
k=2;
backtrack=true;
memoize=true;
*/
1. 語言選項(xiàng) language
語言選項(xiàng)指定了ANTLR將要產(chǎn)生的代碼的目標(biāo)語言,默認(rèn)情況下該選項(xiàng)設(shè)置為了Java。需要注意的是,ANTLR中的嵌入的動(dòng)作必須要使用目標(biāo)語言來寫。
grammar T;
options {
language=Java;
}
ANTLR使用了特有的基于字串模板(StringTemplate-based)代碼生成器,構(gòu)建一個(gè)新的目標(biāo)語言顯得較為簡(jiǎn)單,因此我們可以構(gòu)建多種 語言,諸如Java,C,C++,C#,Python,Objective-C,Ruby等等。語言選項(xiàng)讓ANNTLR去模板目錄(例如 org/antlr/codegen/templates/Java or org/antlr/codegen/templates/C)下尋找合適的模板,并使用模板來構(gòu)建語言。該目錄下包含大量的模板,我們可以向其中加入其 他的模板以滿足我們的需求。
2. 輸出選項(xiàng) output
輸出選項(xiàng)控制了ANTLR輸出的數(shù)據(jù)結(jié)構(gòu),目前支持兩種輸出:抽象語法樹——AST(Abstract Syntax Trees)和字串模板(StringTemplates)——template。當(dāng)output這個(gè)選項(xiàng)被設(shè)置后,所有的規(guī)則都被輸出成了AST或者 template。
grammar T;
options {
output=AST;
}
3. 回溯選項(xiàng)backtrack
當(dāng)回溯選項(xiàng)打開的時(shí)候,在執(zhí)行一個(gè)LL(K)失敗的時(shí)候,ANTLR會(huì)返回至LL(K)開始而嘗試其他的規(guī)則。
4. 記憶選項(xiàng) (memorize)
memoize選項(xiàng)打開以后,每條解析方法(Paser Method)開始之前,ANTLR會(huì)首先檢測(cè)以前的嘗試結(jié)果,并在該方法執(zhí)行完成之后記錄該規(guī)則是否執(zhí)行成功。但是注意,對(duì)于單條的規(guī)則打開此選項(xiàng)經(jīng)常比在全局上打開該規(guī)則效率更高。
5. 記號(hào)詞庫(tokenVocab)
說白了就是output輸出目錄中的XX.tokens文件中的定義可以方便的給 大型工程中多個(gè).g中的符號(hào)同步更新。
大型的工程中常常利用AST作為中間產(chǎn)物對(duì)輸入進(jìn)行多次分析并最終生成代碼。對(duì)AST的遍歷時(shí)需要經(jīng)常使用樹語法(tree grammar),而tree grammar中經(jīng)常需要將符號(hào)與其他的文件中的符號(hào)進(jìn)行同步或者更新。tokenVocab實(shí)現(xiàn)了這個(gè)功能。
例如我們定義了下面的一個(gè)語法文件:
grammar P;
options {
output=AST;
}
expr: INT ('+' ^ INT)* ;
INT : '0'..'9' +;
WS : ' ' | '\r' | '\n' ;
利用該文件生成了一個(gè)標(biāo)記:P.token,并生成了語法樹(AST)。這時(shí)我們需要一個(gè)用于遍歷該AST的tree grammar,并通過tree grammar 中的tokenVocab選項(xiàng)來向其中更新tokens:
tree grammar Dump;
options {
tokenVocab=P;
ASTLabelType=CommonTree;
}
expr: ^( '+' expr {System.out.print('+' );} expr )
| INT {System.out.print($INT.text);}
;
編譯tree grammar的時(shí)候ANTLR默認(rèn)會(huì)在當(dāng)前目錄下尋找.token文件,我們可以通過-lib選項(xiàng)來設(shè)置用于尋找.token文件的目錄,例如:
java org.antlr.Tool -lib . Dump.g
6. 重寫選項(xiàng)(rewrite)
通過重寫選項(xiàng)可以改變ANTLR對(duì)輸入的默認(rèn)處理規(guī)則,一般用在輸出為template的情況下。將該選項(xiàng)使能之后,ANTLR將一般的輸入直接拷貝至輸出,而將適于模板重寫規(guī)則的輸入做其他的處理。
7. 超類選項(xiàng)(superClass)
用于指定一個(gè)超類。
8. 過濾選項(xiàng)(Filter)
9. AST標(biāo)簽類型(ASTLabelType)
10. K選項(xiàng)
K選項(xiàng)用于限制對(duì)LL(K)進(jìn)行語法分析的次數(shù),從而提高了ANTLR的解析速度。K只能為*或者數(shù)字,默認(rèn)為*。
屬性和動(dòng)作
動(dòng)作(Actions)實(shí)際上是用目標(biāo)語言寫成的、嵌入到規(guī)則中的代碼(以花括號(hào)包裹)。它們通常直接操作輸入的標(biāo)號(hào),但是他們也可以用來調(diào)用相應(yīng)的外部代碼。屬性,到目前為止我的理解還不多,感覺像是C++中類里面的成員,一會(huì)看完應(yīng)該會(huì)更清楚一些。
1. 語法動(dòng)作(Grammar Actions)
動(dòng)作(Actions)是指嵌在語法中的、用目標(biāo)語言寫成的代碼片段。ANTLR則把這些代碼(除了用$或%標(biāo)記的以外)逐字地插入到生成的識(shí)別器中。
動(dòng)作可以放到規(guī)則的外邊,也可以嵌入到某條規(guī)則當(dāng)中。當(dāng)動(dòng)作位于規(guī)則之外時(shí)候,這些動(dòng)作同城定義了一些全局的或者是類的成員(變量或者成員函數(shù));而當(dāng)其嵌入規(guī)則之中時(shí),則用于執(zhí)行某些特定的命令,這些命令在識(shí)別器識(shí)別了其預(yù)訂的字符的時(shí)候就會(huì)開始執(zhí)行。例如下面的例子:
parser grammar T;
@header {
package p;
}
@members {
int i;
public TParser(TokenStream input, int foo) {
this(input);
i = foo;
}
}
a[int x] returns [int y]
@init {int z=0;}
@after {System.out.println("after matching rule; before finally");}
: {《action1》} A {《action2 》}
;
catch[RecognitionException re] {
System.err.println("error");
}
finally { 《do-this-no-matter-what 》 }
從中可以看出,前面的兩個(gè)動(dòng)作,@head and @members是兩個(gè)處于規(guī)則之外的全局的動(dòng)作,定義了一些變量和類;而后兩個(gè)則分別在a這個(gè)規(guī)則的前后執(zhí)行(@init在前,@after在后,這個(gè)在前面提到過)。
這里針對(duì)兩種類型詳細(xì)敘述。
antlr簡(jiǎn)介
1. 需要有全職的有威信,有能力的產(chǎn)品負(fù)責(zé)人(PO-Product Owner).
2. PO要和Scrum Team、其他的利益相關(guān)者(stakeholder)一起工作
3. 有PO來創(chuàng)建和管理產(chǎn)品backlog.
4. Scrum每日站會(huì)必須的3個(gè)問題(完成了什么,準(zhǔn)備做什么,有什么障礙)。
5. Scrum每日站會(huì)要在固定的地方時(shí)間不要超過15分鐘。
6. 有規(guī)律的Sprint長度(不超過30天)
7. 在Sprint計(jì)劃會(huì)議上創(chuàng)建Sprint Backlog和經(jīng)過詳細(xì)估算的任務(wù)列表。
8. 一定要有Sprint的燃盡圖。
9. Team必須的設(shè)備及相關(guān)的供應(yīng)要齊全。
10. 使用回顧會(huì)議確保過程在不斷提升。
11. 有明確的對(duì)于“任務(wù)完成”的定義。
12. 按照合理的速率給出承諾(根據(jù)Sprint的工作量估計(jì))。
13. 團(tuán)隊(duì)大小在7 +/- 2,最多不能超過12人
14. 跨職能的團(tuán)隊(duì)包括Scrum Master和PO.
15. 自組織的團(tuán)隊(duì) - 團(tuán)隊(duì)成員志愿挑選任務(wù)。
16. Scrum master要跟蹤進(jìn)度,并且為團(tuán)隊(duì)掃清障礙。
17. 確保Team不被外界干擾。
18. Sprint之間不能間斷。
19. 合理的節(jié)奏 - 根據(jù)固定時(shí)間段來確定任務(wù)量, 不只是一個(gè)進(jìn)度表。
20. 質(zhì)量是第一,不需要在質(zhì)量上討價(jià)還價(jià) - 代碼缺陷永遠(yuǎn)位于Backlog的最上層。
轉(zhuǎn)載于:http://www.infoq.com/cn/articles/skills-for-scrum-agile-teams
敏捷項(xiàng)目的工程獨(dú)特性
1. 設(shè)置開發(fā)環(huán)境
在傳統(tǒng)項(xiàng)目中,團(tuán)隊(duì)可以投入充分的時(shí)間來設(shè)置開發(fā)環(huán)境;而在敏捷團(tuán)隊(duì)里面,他們需要從第一刻時(shí)間起就能產(chǎn)出。根據(jù)我們的經(jīng)驗(yàn),我們認(rèn)識(shí)到缺乏設(shè)置開發(fā)環(huán)境的相關(guān)文檔是設(shè)置環(huán)境如此耗時(shí)的一個(gè)關(guān)鍵原因。第二個(gè)關(guān)鍵原因是在設(shè)置過程中涉及的手工步驟數(shù)。在第0次sprint,我們必須記錄每一件開發(fā)人員必須做了才能開始編寫代碼,并集成團(tuán)隊(duì)其他人工作的小事。
2. 自動(dòng)構(gòu)建
讓我們盡早失敗!我們領(lǐng)悟到,手工構(gòu)建可能既脆弱,又特定于某一臺(tái)機(jī)器,而且當(dāng)時(shí)間耗費(fèi)在手工構(gòu)建的基礎(chǔ)工作上面時(shí),開發(fā)和測(cè)試的時(shí)間就被擠占掉了。除去最小的項(xiàng)目,自動(dòng)構(gòu)建過程對(duì)于每一個(gè)項(xiàng)目都是必不可少的。我們認(rèn)識(shí)到,即使需要抽出時(shí)間來創(chuàng)建自動(dòng)構(gòu)建的環(huán)境,你以后是能把這些時(shí)間賺回來的。這也使得我們更易于確保項(xiàng)目有一個(gè)人人共有的標(biāo)準(zhǔn)化構(gòu)建。
3. 持續(xù)集成
根據(jù)我們過去的經(jīng)驗(yàn),我們領(lǐng)悟到,等到最后的幾個(gè)星期才去把不同團(tuán)隊(duì)成員的代碼集成到一起是一個(gè)災(zāi)難。如果你已經(jīng)擁有了自動(dòng)構(gòu)建,接下來的事情就是持續(xù)集成。當(dāng)然,版本控制(或者軟件配置管理——另一個(gè)更為正式的和令人印象深刻的名字)是自動(dòng)構(gòu)建和持續(xù)集成環(huán)境的前提。我們學(xué)到的一個(gè)重要教訓(xùn)是,你越快識(shí)別出集成的錯(cuò)誤,你就能越快地解決這些問題。我們?cè)?jīng)使用過的主要工具包括 CruiseControl、CruiseControl.Net和Bamboo。 hadson,基礎(chǔ)集成還是不錯(cuò)的。
4. 單元測(cè)試
在高度流動(dòng)的環(huán)境中,隨著多個(gè)開發(fā)人員一起工作、需求的變更和優(yōu)先級(jí)的不斷變化,確保昨天可以運(yùn)行的東西今天也能運(yùn)行,這是至關(guān)重要的。此外,我們還要與集成出現(xiàn)的錯(cuò)誤為戰(zhàn)。一種方法(我們從艱難歲月中學(xué)習(xí)得來)是使用單元測(cè)試,這樣代碼的更改不會(huì)破壞現(xiàn)有的功能。我們也開始在開發(fā)編碼之前編寫單元測(cè)試用例。我們?cè)?jīng)使用過的主要工具包括JUnit(以及其他的xUnit工具如NUnit、HttpUnit等)和MockObjects。
5. 重構(gòu)
在傳統(tǒng)的項(xiàng)目中,通常有一個(gè)人保護(hù)他們的代碼庫,直到代碼集成階段。但是在敏捷里面,我們持代碼集體所有制的觀點(diǎn)——所有的代碼屬于所有的開發(fā)人員,只要開發(fā)人員認(rèn)為有必要,每個(gè)人都能不受約束地去改善代碼。在一段時(shí)間里面,我們的代碼庫開始出現(xiàn)奇怪的行為——解決辦法就是重構(gòu)(感謝Martin Fowler在他的同名著作中把重構(gòu)一詞推廣開來)。重構(gòu)的本質(zhì)歸結(jié)為修改代碼以改善代碼的結(jié)構(gòu)和清晰度,但不改變代碼的功能。我們學(xué)到的一個(gè)重要教訓(xùn)是在重構(gòu)代碼之前使用單元測(cè)試作為安全網(wǎng),我們?cè)?jīng)使用過的一些主要工具包括Eclipse、NetBeans、IntelliJ IDEA的和Visual Studio.NET。
在敏捷團(tuán)隊(duì)之中工作所必備的行為特征
由于敏捷團(tuán)隊(duì)不同于普通的團(tuán)隊(duì),并且非常倚賴于有效果和有效率的溝通和快速執(zhí)行,敏捷團(tuán)隊(duì)更需要使用軟技能。如果我們意識(shí)到這一點(diǎn),并積極鼓勵(lì)使用這些特征和技能,我們可以使得敏捷團(tuán)隊(duì)更有價(jià)值和富有成效。
自組織往往倚賴于諸如正反饋、負(fù)反饋、深度探索和廣度調(diào)研之間取得平衡以及多重互動(dòng)的基本要素。根據(jù)我們的經(jīng)驗(yàn),團(tuán)隊(duì)可能由于許多文化和社會(huì)因素?zé)o法給予正確的反饋或者回避人與人之間的互動(dòng)。
根據(jù)我個(gè)人的經(jīng)驗(yàn),這仍然是一個(gè)“神話”。我們總是傾向于患有“可預(yù)測(cè)性綜合癥”——如果我們做更多的規(guī)劃,我們將更加功能預(yù)測(cè)。
團(tuán)隊(duì)需要有良好的紀(jì)律、有能力承擔(dān)責(zé)任、盡忠盡責(zé)以及承擔(dān)職責(zé)和所有權(quán)。
團(tuán)隊(duì)需要擁有的關(guān)鍵技能之一是有能力尋求幫助,并尋求他人的評(píng)價(jià)。在某些情形下,我們已經(jīng)看到了“自我”因素表現(xiàn)為一個(gè)主要的障礙。
有些時(shí)候,承擔(dān)責(zé)任,盡忠盡責(zé)和協(xié)作精神是理所當(dāng)然的,但是根據(jù)以往的經(jīng)驗(yàn),為了這些能夠出現(xiàn),我們有時(shí)需要外部干預(yù)。
有些我們常常傾向于忽視的關(guān)鍵技能是積極主動(dòng)、在激烈的環(huán)境中享受工作和易于適應(yīng)新的形勢(shì)和框架。
我們的大多數(shù)項(xiàng)目都是分布式的,這意味著在客戶和服務(wù)供應(yīng)商之間將會(huì)共同使用Scrum。在這種情況下,諸如管理多樣化團(tuán)隊(duì)、時(shí)間管理、外交技巧和領(lǐng)導(dǎo)力等技能是非常關(guān)鍵的。
敏捷團(tuán)隊(duì)的成功“咒語”
對(duì)于任何一個(gè)希望成功和高效的敏捷項(xiàng)目,團(tuán)隊(duì)需要對(duì)向同儕學(xué)習(xí)(不管資歷和專業(yè)知識(shí))表現(xiàn)出更大的熱情和正確的態(tài)度。必須保證一個(gè)無畏表達(dá)的安全網(wǎng),這樣才會(huì)展現(xiàn)出真正的友情,而這反過來會(huì)增強(qiáng)團(tuán)隊(duì)成員對(duì)團(tuán)隊(duì)目標(biāo)的關(guān)注,而不是“哪些由我來做”?
結(jié)論
根據(jù)我個(gè)人的經(jīng)驗(yàn)和觀察,對(duì)于提高生產(chǎn)率所需的技能,敏捷項(xiàng)目與傳統(tǒng)項(xiàng)目有所不同。本文定義了團(tuán)隊(duì)提高生產(chǎn)率所需的行為和技術(shù)技能。具有這些“delta” 特征的人應(yīng)該具備了合適的行為和技術(shù)技能,這些技能使得他們?cè)诿艚蓓?xiàng)目中的工作能夠富有成效。對(duì)于這些技能的總結(jié)請(qǐng)見下表。
技能表
角色 |
技術(shù)技能(在不同的方面) |
行為技能 |
開發(fā)人員 |
CRUD操作,開發(fā)框架不同層之間的調(diào)用 單元測(cè)試(工具——NUnit、JUnit) 代碼覆蓋率的概念和工具 代碼審查的概念和工具 持續(xù)集成工具 重構(gòu)的概念 代碼味道的概念 Scrum過程 |
溝通 合作 時(shí)間管理/計(jì)劃 思維 沖突管理 處理更改/靈活性 決策 團(tuán)隊(duì)合作/團(tuán)隊(duì)建設(shè) 處理壓力 問題解決 領(lǐng)導(dǎo) 外交 |
QA |
“完成”的定義 —> 驗(yàn)收標(biāo)準(zhǔn) 測(cè)試管理 自動(dòng)化/腳本 環(huán)境設(shè)置 數(shù)據(jù)庫概念 |
與開發(fā)人員相同 |
Scrum Master |
Scrum過程 模板和使用 項(xiàng)目管理工具 持續(xù)集成工具 設(shè)置開發(fā)環(huán)境 |
開發(fā)人員的技能+推動(dòng)力 |
作者簡(jiǎn)介
Prasad,擁有10年的IT服務(wù)行業(yè)經(jīng)驗(yàn),他第一次接觸敏捷項(xiàng)目是在2005年微軟的一個(gè)項(xiàng)目;從那時(shí)起,他為許多公司如GE、思科、可口可樂等,針對(duì)敏捷及其變體提供了解決方案開發(fā)、培訓(xùn)、咨詢以及指導(dǎo)。目前他正在Symphony Services的敏捷實(shí)驗(yàn)室擔(dān)任經(jīng)理。Symphony40%的項(xiàng)目都是關(guān)于敏捷或其不同的形式,并且自2004年起就通過敏捷為客戶提供商務(wù)的關(guān)鍵價(jià)值。你可以通過pprabhak@symphonsysv.com與他聯(lián)系。
查看英文原文:Skills for Scrum Agile Teams
敏捷最大的特點(diǎn)是:不但快,反應(yīng)要更快。
最終的目的是:提升效率。
敏捷是一種思想:
溝通:個(gè)體交互
簡(jiǎn)單:快速交付
反饋:客戶合作
勇氣:響應(yīng)變化
關(guān)鍵條件還是目標(biāo)一直的團(tuán)隊(duì)
共同愿景
高效溝通
互相信任
嚴(yán)格執(zhí)行
迅速迭代,越變?cè)矫溃试S試錯(cuò)
敏捷精華: 小勝+ 反思
1.現(xiàn)在列出你認(rèn)為你能完成的一件事。
比如我認(rèn)為每天30分鐘的話,下一周我能讀一本書:書名叫《人人都是產(chǎn)品經(jīng)理》
2.每天把進(jìn)度記錄到地下
我會(huì)把讀完的頁數(shù)寫出來,加上一點(diǎn)點(diǎn)感想
看完后,總結(jié)下。
任何一個(gè)有經(jīng)驗(yàn)的程序員都知道,軟件開發(fā)遵循著一些不成文的法則。然而,如果你不遵循這些法則也并不意味著會(huì)受到懲罰;相反,有時(shí)你還會(huì)獲得意外的好處。下面的就是軟件編程中的21條法則:
- 任何程序一旦部署即顯陳舊。
- 修改需求規(guī)范來適應(yīng)程序比反過來做更容易。
- 一個(gè)程序如果很有用,那它注定要被改掉。
- 一個(gè)程序如果沒用,那它一定會(huì)有很好的文檔。
- 任何程序里都僅僅只有10%的代碼會(huì)被執(zhí)行到。
- 軟件會(huì)一直膨脹到耗盡所有資源為止。
- 任何一個(gè)有點(diǎn)價(jià)值的程序里都會(huì)有至少一個(gè)bug。
- 原型完美的程度跟審視的人數(shù)成反比,反比值會(huì)隨著涉及的資金數(shù)增大。
- 軟件直到被變成產(chǎn)品運(yùn)行至少6個(gè)月后,它最嚴(yán)重的問題才會(huì)被發(fā)現(xiàn)。
- 無法檢測(cè)到的錯(cuò)誤的形式無限多樣,而能被檢測(cè)到的正好相反,被定義了的十分有限。
- 修復(fù)一個(gè)錯(cuò)誤所需要投入的努力會(huì)隨著時(shí)間成指數(shù)級(jí)增加。
- 軟件的復(fù)雜度會(huì)一直增加,直到超出維護(hù)這個(gè)程序的人的承受能力。
- 任何自己的程序,幾個(gè)月不看,形同其他人寫的。
- 任何一個(gè)小程序里面都有一個(gè)巨大的程序蠢蠢欲出。
- 編碼開始的越早,花費(fèi)的時(shí)間越長。
- 一個(gè)粗心的項(xiàng)目計(jì)劃會(huì)讓你多花3倍的時(shí)間去完成;一個(gè)細(xì)心的項(xiàng)目計(jì)劃只會(huì)讓你多花2倍的時(shí)間。
- 往大型項(xiàng)目里添加人手會(huì)使項(xiàng)目更延遲。
- 一個(gè)程序至少會(huì)完成90%,但永遠(yuǎn)完成不了超過95%。
- 如果你想麻煩被自動(dòng)處理掉,你得到的是自動(dòng)產(chǎn)生的麻煩。
- 開發(fā)一個(gè)傻瓜都會(huì)使用的軟件,只有傻瓜愿意使用它。
- 用戶不會(huì)真正的知道要在軟件里做些什么,除非使用過。
public class CheckQueryParams {
private static interface Validation{
void check(QueryInfo query);
}
private static List<Validation> validations = new ArrayList<Validation>();
static {
validations.add(new Validation() {
public void check(QueryInfo query) {
if(StringUtils.isEmpty(query.getStartKey()) && StringUtils.isEmpty(query.getEndKey()))
throw new RuntimeException("Both keys can not be null or empty at the same time");
}});
}
public static void check(QueryInfo query) {
for(Validation validation : validations) {
validation.check(query);
}
}
}
public class LRUCache<K,V> {
final private int capacity;
final private Map<K,Reference<V>> map;
final private ReentrantLock lock = new ReentrantLock();
final private ReferenceQueue<Reference<V>> queue = new ReferenceQueue<Reference<V>>();
public LRUCache(int capacity) {
this.capacity = capacity;
map = new LinkedHashMap<K,Reference<V>>(capacity,1f,true){
@Override
protected boolean removeEldestEntry(Map.Entry<K,Reference<V>> eldest) {
return this.size() > LRUCache.this.capacity;
}
};
}
public V put(K key,V value) {
lock.lock();
try {
map.put(key, new SoftReference(value,queue));
return value;
}finally {
lock.unlock();
}
}
public V get(K key) {
lock.lock();
try {
queue.poll();
return map.get(key).get();
}finally {
lock.unlock();
}
}
public void remove(K key) {
lock.lock();
try {
map.remove(key);
}finally {
lock.unlock();
}
}
}
對(duì)于局部變量和參數(shù)來說,java里面的int, float, double, boolean等基本數(shù)據(jù)類型,都在棧上。這些基本類型是無法同步的;java里面的對(duì)象(根對(duì)象是Object),全都在堆里,指向?qū)ο蟮膔eference在棧上。
java中的同步對(duì)象,實(shí)際上是對(duì)于reference所指的“對(duì)象地址”進(jìn)行同步。
需要注意的問題是,千萬不要對(duì)同步對(duì)象重新賦值。舉個(gè)例子。
class A implements Runnable{
Object lock = new Object();
void run(){
for(...){
synchronized(lock){
// do something
...
lock = new Object();
}
}
}
}
run函數(shù)里面的這段同步代碼實(shí)際上是毫無意義的。因?yàn)槊恳淮蝜ock都給重新分配了新的對(duì)象的reference,每個(gè)線程都在新的reference同步。大家可能覺得奇怪,怎么會(huì)舉這么一個(gè)例子。因?yàn)槲乙娺^這樣的代碼,同步對(duì)象在其它的函數(shù)里被重新賦了新值。這種問題很難查出來。所以,一般應(yīng)該把同步對(duì)象聲明為final。 final Object lock = new Object();
使用Singleton Pattern 設(shè)計(jì)模式來獲取同步對(duì)象,也是一種很好的選擇。
2.如何放置共享數(shù)據(jù),粒度,跨類的同步對(duì)象
實(shí)現(xiàn)線程,有兩種方法,一種是繼承Thread類,一種是實(shí)現(xiàn)Runnable接口。
首先,把需要共享的數(shù)據(jù)放在一個(gè)實(shí)現(xiàn)Runnable接口的類里面,然后,把這個(gè)類的實(shí)例傳給多個(gè)Thread的構(gòu)造方法。這樣,新創(chuàng)建的多個(gè)Thread,都共同擁有一個(gè)Runnable實(shí)例,共享同一份數(shù)據(jù)。如果采用繼承Thread類的方法,就只好使用static靜態(tài)成員了。如果共享的數(shù)據(jù)比較多,就需要大量的static靜態(tài)成員,令程序數(shù)據(jù)結(jié)構(gòu)混亂,難以擴(kuò)展。這種情況應(yīng)該盡量避免。編寫一段多線程代碼,處理一個(gè)稍微復(fù)雜點(diǎn)的問題。兩種方法的優(yōu)劣,一試便知。
線程同步的粒度越小越好,即,線程同步的代碼塊越小越好。盡量避免用synchronized修飾符來聲明方法。盡量使用synchronized(anObject)的方式,如果不想引入新的同步對(duì)象,使用synchronized(this)的方式。而且,synchronized代碼塊越小越好。
對(duì)于簡(jiǎn)單的問題,可以把訪問共享資源的同步代碼都放在一個(gè)類里面。
但是對(duì)于復(fù)雜的問題,我們需要把問題分為幾個(gè)部分來處理,需要幾個(gè)不同的類來處理問題。這時(shí),就需要在不同的類中,共享同步對(duì)象。比如,在生產(chǎn)者和消費(fèi)者之間共享同步對(duì)象,在讀者和寫者之間共享同步對(duì)象。
如何在不同的類中,共享同步對(duì)象。有幾種方法實(shí)現(xiàn),
(1)前面講過的方法,使用static靜態(tài)成員,(或者使用Singleton Pattern.)
(2)用參數(shù)傳遞的方法,把同步對(duì)象傳遞給不同的類。
(3)利用字符串常量的“原子性”。
對(duì)于第三種方法,這里做一下解釋。一般來說,程序代碼中的字符串常量經(jīng)過編譯之后,都具有唯一性,即,內(nèi)存中不會(huì)存在兩份相同的字符串常量。
(通常情況下,C++,C語言程序編譯之后,也具有同樣的特性。)
比如,我們有如下代碼。
String A = “atom”;
String B = “atom”;
我們有理由認(rèn)為,A和B指向同一個(gè)字符串常量。即,A==B。注意,聲明字符串變量的代碼,不符合上面的規(guī)則。
String C= new String(“atom”);
String D = new String(“atom”);
這里的C和D的聲明是字符串變量的聲明,所以,C != D。
有了上述的認(rèn)識(shí),我們就可以使用字符串常量作為同步對(duì)象。比如我們?cè)诓煌念愔校褂胹ynchronized(“myLock”), “myLock”.wait(),“myLock”.notify(), 這樣的代碼,就能夠?qū)崿F(xiàn)不同類之間的線程同步。本文并不強(qiáng)烈推薦這種用法,只是說明,有這樣一種方法存在。本文推薦第二種方法,(2)用參數(shù)傳遞的方法,把同步對(duì)象傳遞給不同的類。
3.線程之間的通知
這里使用“通知”這個(gè)詞,而不用“通信”這個(gè)詞,是為了避免詞義的擴(kuò)大化。
線程之間的通知,通過Object對(duì)象的wait()和notify() 或notifyAll() 方法實(shí)現(xiàn)。
下面用一個(gè)例子,來說明其工作原理:
假設(shè)有兩個(gè)線程,A和B。共同擁有一個(gè)同步對(duì)象,lock。
1.首先,線程A通過synchronized(lock) 獲得lock同步對(duì)象,然后調(diào)用lock.wait()函數(shù),放棄lock同步對(duì)象,線程A停止運(yùn)行,進(jìn)入等待隊(duì)列。
2.線程B通過synchronized(lock) 獲得線程A放棄的lock同步對(duì)象,做完一定的處理,然后調(diào)用 lock.notify() 或者lock.notifyAll() 通知等待隊(duì)列里面的線程A。
3.線程A從等待隊(duì)列里面出來,進(jìn)入ready隊(duì)列,等待調(diào)度。
4.線程B繼續(xù)處理,出了synchronized(lock)塊之后,放棄lock同步對(duì)象。
5.線程A獲得lock同步對(duì)象,繼續(xù)運(yùn)行。
例子代碼如下:
public class SharedResource implements Runnable{
Object lock = new Object();
public void run(){
// 獲取當(dāng)前線程的名稱。
String threadName = Thread.currentThread().getName();
if( “A”.equals(threadName)){
synchronized(lock){ //線程A通過synchronized(lock) 獲得lock同步對(duì)象
try{
System.out.println(“ A gives up lock.”);
lock.wait(); // 調(diào)用lock.wait()函數(shù),放棄lock同步對(duì)象,
// 線程A停止運(yùn)行,進(jìn)入等待隊(duì)列。
}catch(InterruptedException e){
}
// 線程A重新獲得lock同步對(duì)象之后,繼續(xù)運(yùn)行。
System.out.println(“ A got lock again and continue to run.”);
} // end of synchronized(lock)
}
if( “B”.equals(threadName)){
synchronized(lock){//線程B通過synchronized(lock) 獲得線程A放棄的lock同步對(duì)象
System.out.println(“B got lock.”);
lock.notify(); //通知等待隊(duì)列里面的線程A,進(jìn)入ready隊(duì)列,等待調(diào)度。
//線程B繼續(xù)處理,出了synchronized(lock)塊之后,放棄lock同步對(duì)象。
System.out.println(“B gives up lock.”);
} // end of synchronized(lock)
boolean hasLock = Thread.holdsLock(lock); // 檢查B是否擁有l(wèi)ock同步對(duì)象。
System.out.println(“B has lock ? -- ” +hasLock); // false.
}
}
}
public class TestMain{
public static void main(){
Runnable resource = new SharedResource();
Thread A = new Thread(resource,”A”);
A.start();
// 強(qiáng)迫主線程停止運(yùn)行,以便線程A開始運(yùn)行。
try {
Thread.sleep(500);
}catch(InterruptedException e){
}
Thread B = new Thread(resource,”B”);
B.start();
}
}
http://coolszy.javaeye.com/blog/588627 作者:coolszy
1,朋友請(qǐng)你吃飯,不要覺得理所當(dāng)然,請(qǐng)禮尚往來,否則你的名聲會(huì)越來越臭。
2,給自己定目標(biāo),一年,兩年,五年,也許你出生不如別人好,通過努力,往往可以改變70(百分號(hào))的命運(yùn)。破罐子破摔只能和懦弱做朋友。
3,這是個(gè)現(xiàn)實(shí)的社會(huì),感情不能當(dāng)飯吃,貧窮夫妻百事哀。不要相信電影,那只是個(gè)供許多陌生人喧囂情感的場(chǎng)所。
4,好朋友里面,一定要培養(yǎng)出一個(gè)知己,不要以為你有多么八面玲瓏,到處是朋友,最后真心對(duì)你的,只有一個(gè),相信我。
5,不要相信星座命理,那是哄小朋友的,命運(yùn)在自己手中。難道你想等出棟房子或是車子?
6,不喜歡的人少接觸,但別在背后說壞話,說是非之人,必定是是非之人,謹(jǐn)記,禍從口出。
7,少玩游戲,這不是韓國,你打不出房子車子還有女人。
8,學(xué)好英語,那些說學(xué)英語沒用的暫時(shí)可以不去管,他們要么年紀(jì)大了,要么就是自己早過了CET6準(zhǔn)備托福了,在這里嘩眾取寵。你可以不拿證,但一定要學(xué)好。
9,知道自己要干什么,夜深人靜,問問自己,將來的打算,并朝著那個(gè)方向去實(shí)現(xiàn)。
10,偶爾翻翻時(shí)尚類的雜志,提高一下自己的品位。
11,盡量少看OOXX,正常的男人即使是單身,也不會(huì)成天迷戀OOXX。而每次你SY后都會(huì)有大量鋅元素流失,此元素與你大腦活動(dòng)有密切聯(lián)系。
12,每天早上一杯水,預(yù)防膽結(jié)石。睡前一小時(shí)不要喝水,否則會(huì)過早出現(xiàn)眼袋。
13,空閑時(shí)間不要全拿去泡BAR,讀點(diǎn)文學(xué)作品,學(xué)習(xí)一些經(jīng)營流程,管理規(guī)范,國際時(shí)事,法律常識(shí)。這能保證你在任何場(chǎng)合都有談資。
14,大家都年輕,沒什么錢,不用太在意誰誰又穿AD ,NIKE ,或者其他。而GF對(duì)于PRADA,蘭蔻,CD,LV,的熱戀,你也不必放在心上,女人天生和美掛上了勾,她們只是寧愿相信你能夠?yàn)樗齻冑I一樣昂貴的禮物,以滿足她們的虛榮心,然后在同伴面前炫耀一番。實(shí)則她們也是熱愛生活的,而當(dāng)你有能力完成時(shí),也會(huì)覺得把她包裝得漂漂亮亮的很是欣慰。
15,要做一件事,成功之前,沒必要告訴其他人。
16,頭發(fā),指甲,胡子,打理好。社會(huì)是個(gè)排斥性的接受體,這個(gè)星球所需要的藝術(shù)家極其有限,請(qǐng)不要冒這個(gè)險(xiǎn),就算你留長頭發(fā)比較好看,也要盡量給人干凈的感覺。
17,不要以為你是個(gè)男人,就不需要保養(yǎng)。至少飲食方面不能太隨便,多吃番茄,海產(chǎn)品,韭菜,香蕉,都是對(duì)男性健康有益處的食物。你要是看不到價(jià)值,我可以告訴你。至少你能把看病節(jié)約下來的錢給你的女人多買幾個(gè)DIOR.
18,力求上進(jìn)的人,不要總想著靠誰誰,人都是自私的,自己才是最靠得住的人。
19,面對(duì)失敗,不要太計(jì)較,天將降大任于斯人也,必先苦其心志,勞其筋骨,餓起體膚……但要學(xué)會(huì)自責(zé),找到原因,且改掉壞習(xí)慣。 二十歲沒錢,那很正常;三十歲沒錢,那是宿命;四十歲沒錢,那是你已經(jīng)成為女人了。
一.介紹 (不想看直接可以跳過)
Rsync是一個(gè)遠(yuǎn)程數(shù)據(jù)同步工具,可通過LAN/WAN快速同步多臺(tái)主機(jī)間的文件。Rsync本來是用以取代rcp的一個(gè)工具,它當(dāng)前由 rsync.samba.org維護(hù)。Rsync使用所謂的“Rsync演算法”來使本地和遠(yuǎn)程兩個(gè)主機(jī)之間的文件達(dá)到同步,這個(gè)算法只傳送兩個(gè)文件的不同部分,而不是每次都整份傳送,因此速度相當(dāng)快。運(yùn)行Rsync server的機(jī)器也叫backup server,一個(gè)Rsync server可同時(shí)備份多個(gè)client的數(shù)據(jù);也可以多個(gè)Rsync server備份一個(gè)client的數(shù)據(jù)。
Rsync可以搭配rsh或ssh甚至使用daemon模式。Rsync server會(huì)打開一個(gè)873的服務(wù)通道(port),等待對(duì)方Rsync連接。連接時(shí),Rsync server會(huì)檢查口令是否相符,若通過口令查核,則可以開始進(jìn)行文件傳輸。第一次連通完成時(shí),會(huì)把整份文件傳輸一次,下一次就只傳送二個(gè)文件之間不同的部份。
Rsync支持大多數(shù)的類Unix系統(tǒng),無論是Linux、Solaris還是BSD上都經(jīng)過了良好的測(cè)試。此外,它在windows平臺(tái)下也有相應(yīng)的版本,比較知名的有cwRsync和Sync2NAS。
Rsync的基本特點(diǎn)如下:
1.可以鏡像保存整個(gè)目錄樹和文件系統(tǒng);
2.可以很容易做到保持原來文件的權(quán)限、時(shí)間、軟硬鏈接等;
3.無須特殊權(quán)限即可安裝;
4.優(yōu)化的流程,文件傳輸效率高;
5.可以使用rcp、ssh等方式來傳輸文件,當(dāng)然也可以通過直接的socket連接;
6.支持匿名傳輸。
核心算法介紹:
假定在名為α和β的兩臺(tái)計(jì)算機(jī)之間同步相似的文件A與B,其中α對(duì)文件A擁有訪問權(quán),β對(duì)文件B擁有訪問權(quán)。并且假定主機(jī)α與β之間的網(wǎng)絡(luò)帶寬很小。那么rsync算法將通過下面的五個(gè)步驟來完成:
1.β將文件B分割成一組不重疊的固定大小為S字節(jié)的數(shù)據(jù)塊。最后一塊可能會(huì)比S 小。
2.β對(duì)每一個(gè)分割好的數(shù)據(jù)塊執(zhí)行兩種校驗(yàn):一種是32位的滾動(dòng)弱校驗(yàn),另一種是128位的MD4強(qiáng)校驗(yàn)。
3.β將這些校驗(yàn)結(jié)果發(fā)給α。
4.α通過搜索文件A的所有大小為S的數(shù)據(jù)塊(偏移量可以任選,不一定非要是S的倍數(shù)),來尋找與文件B的某一塊有著相同的弱校驗(yàn)碼和強(qiáng)校驗(yàn)碼的數(shù)據(jù)塊。這項(xiàng)工作可以借助滾動(dòng)校驗(yàn)的特性很快完成。
5.α發(fā)給β一串指令來生成文件A在β上的備份。這里的每一條指令要么是對(duì)文件B經(jīng)擁有某一個(gè)數(shù)據(jù)塊而不須重傳的證明,要么是一個(gè)數(shù)據(jù)塊,這個(gè)數(shù)據(jù)塊肯定是沒有與文件B的任何一個(gè)數(shù)據(jù)塊匹配上的。
命令:
rsync的命令格式可以為以下六種:
rsync [OPTION]... SRC DEST
rsync [OPTION]... SRC [USER@]HOST:DEST
rsync [OPTION]... [USER@]HOST:SRC DEST
rsync [OPTION]... [USER@]HOST::SRC DEST
rsync [OPTION]... SRC [USER@]HOST::DEST
rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]
對(duì)應(yīng)于以上六種命令格式,rsync有六種不同的工作模式:
1)拷貝本地文件。當(dāng)SRC和DES路徑信息都不包含有單個(gè)冒號(hào)":"分隔符時(shí)就啟動(dòng)這種工作模式。
2)使用一個(gè)遠(yuǎn)程shell程序(如rsh、ssh)來實(shí)現(xiàn)將本地機(jī)器的內(nèi)容拷貝到遠(yuǎn)程機(jī)器。當(dāng)DST路徑地址包含單個(gè)冒號(hào)":"分隔符時(shí)啟動(dòng)該模式。
3)使用一個(gè)遠(yuǎn)程shell程序(如rsh、ssh)來實(shí)現(xiàn)將遠(yuǎn)程機(jī)器的內(nèi)容拷貝到本地機(jī)器。當(dāng)SRC地址路徑包含單個(gè)冒號(hào)":"分隔符時(shí)啟動(dòng)該模式。
4)從遠(yuǎn)程rsync服務(wù)器中拷貝文件到本地機(jī)。當(dāng)SRC路徑信息包含"::"分隔符時(shí)啟動(dòng)該模式。
5)從本地機(jī)器拷貝文件到遠(yuǎn)程rsync服務(wù)器中。當(dāng)DST路徑信息包含"::"分隔符時(shí)啟動(dòng)該模式。
6)列遠(yuǎn)程機(jī)的文件列表。這類似于rsync傳輸,不過只要在命令中省略掉本地機(jī)信息即可。
二.安裝
1.從原始網(wǎng)站下載:[url]http://rsync.samba.org/ftp/rsync/[/url] (http://rsync.samba.org/ftp/rsync/rsync-3.0.7.tar.gz目前是這個(gè)版本)
windows版本:
客戶端:cwRsync_2.0.10_Installer http://blogimg.chinaunix.net/blog/upfile/070917224721.zip
服務(wù)端:cwRsync_Server_2.0.10_Installer http://blogimg.chinaunix.net/blog/upfile/070917224837.zip
對(duì)于client 和 server都是windows的,那么可以直接安裝如上2個(gè),然后可以通過建 windows的任務(wù),實(shí)現(xiàn)定時(shí)處理,可以參考:
http://blog.csdn.net/daizhj/archive/2009/11/03/4765280.aspx
2.[root@localhost bin]#./configure
[root@localhost bin]#make
[root@localhost bin]#make install
這里可能會(huì)有權(quán)限問題,切換到root用戶
Rsync配置
/etc/rsyncd.conf (默認(rèn)是沒有的,可以手工創(chuàng)建)
#全局選項(xiàng)
strict modes =yes #是否檢查口令文件的權(quán)限
port = 873 #默認(rèn)端口873
log file = /var/log/rsyncd.log #日志記錄文件 原文中有的,我沒有使用,日志文件
pid file = /usr/local/rsync/rsyncd.pid #運(yùn)行進(jìn)程的ID寫到哪里 原文中有的,我沒有使用,日志文件
#模塊選項(xiàng)
[test] # 這里是認(rèn)證的模塊名,在client端需要指定
max connections = 5 #客戶端最大連接數(shù),默認(rèn)0(沒限制)
uid = root #指定該模塊傳輸文件時(shí)守護(hù)進(jìn)程應(yīng)該具有的uid
gid = root #指定該模塊傳輸文件時(shí)守護(hù)進(jìn)程應(yīng)該具有的gid
path = /home/admin/testrsync # 需要做備份的目錄
ignore errors # 可以忽略一些無關(guān)的IO錯(cuò)誤
read only = no #no客戶端可上傳文件,yes只讀
write only = no #no客戶端可下載文件,yes不能下載
hosts allow = * #充許任何主機(jī)連接
hosts deny = 10.5.3.77 #禁止指定的主機(jī)連接
auth users = root # 認(rèn)證的用戶名,如果沒有這行,則表明是匿名
secrets file = /home/admin/security/rsync.pass # 指定認(rèn)證口令文件位置
生成rsync密碼文件
在server端生成一個(gè)密碼文件/home/admin/security/rsync.pass
vi rsync.pass
root:hell05a
注意:密碼文件的權(quán)限,是由rsyncd.conf里的參數(shù)
strict modes =yes/no 來決定
Rsync 的啟動(dòng)
rsycn 的啟動(dòng)方式有多種,我們?cè)谶@里介紹以下幾種:
●. 守護(hù)進(jìn)程方式:(我現(xiàn)在只使用這個(gè))
/usr/local/bin/rsync --daemon
驗(yàn)證啟動(dòng)是否成功
ps -aux |grep rsync
root 59120 0.0 0.2 1460 972 ?? Ss 5:20PM 0:00.00 /usr/local/rsync/bin/rsync –daemon
netstat -an |grep 873
tcp4 0 0 *.873 *.* LISTEN
結(jié)束進(jìn)程:kill -9 pid的值
kill -15 進(jìn)程名
如果是linux之間同步,只需要安裝rsync,如果是需要linux與windows之間同步,安裝 cwrsync
三.客戶端訪問:(客戶端也需要安裝 rsync,如果是windows,安裝cwrsync)
實(shí)例演示使用:
下載文件:
./rsync -vzrtopg --progress --delete root@xxx.xxx.xxx.xxx::backup /home/admin/getfile
上傳文件:
/usr/bin/rsync -vzrtopg --progress /home/admin/getfile root@xxx.xxx.xxx.xxx::backup
Rsync 同步參數(shù)說明
-vzrtopg里的v是verbose,z是壓縮,r是recursive,topg都是保持文件原有屬性如屬主、時(shí)間的參數(shù)。
--progress是指顯示出詳細(xì)的進(jìn)度情況
--delete是指如果服務(wù)器端刪除了這一文件,那么客戶端也相應(yīng)把文件刪除
root@xxx.xxx.xxx.xxx中的root是指定密碼文件中的用戶名,xxx為ip地址
backup 是指在rsyncd.conf里定義的模塊名
/home/admin/getfile 是指本地要備份目錄
可能出現(xiàn)的問題:
@ERROR: auth failed on module backup
rsync error: error starting client-server protocol (code 5) at main.c(1506) [Receiver=3.0.7]
那估計(jì)是密碼文件沒有設(shè)置權(quán)限哦: chmod 600 /home/admin/security/rsync.pass
應(yīng)該差不多就可以了。
(2)打開rsync服務(wù)
#chkconfig xinetd on
#chkconfig rsync on
(4)啟動(dòng)基于xinetd進(jìn)程的rsync服務(wù)t
#/etc/init.d/xinetd start
3、配置windows的rsync客戶端
(1)安裝client端的rsync包
(2)打開cmd,執(zhí)行同步計(jì)劃:
cd C:\Program Files\cwRsync\bin
下載同步(把服務(wù)器上的東東下載當(dāng)前目錄)
rsync -vzrtopg --progress --delete root@xxx.xxx.xxx.xxx::backup ./ff
(此時(shí)須輸入root用戶的密碼,就可進(jìn)行同步了。)
上傳同步(把本地東東上傳到服務(wù)器)
rsync -vzrtopg --progress ./get/ root@xxx.xxx.xxx.xxx::backup
參數(shù)說明
-v, --verbose 詳細(xì)模式輸出
-q, --quiet 精簡(jiǎn)輸出模式
-c, --checksum 打開校驗(yàn)開關(guān),強(qiáng)制對(duì)文件傳輸進(jìn)行校驗(yàn)
-a, --archive 歸檔模式,表示以遞歸方式傳輸文件,并保持所有文件屬性,等于-rlptgoD
-r, --recursive 對(duì)子目錄以遞歸模式處理
-R, --relative 使用相對(duì)路徑信息
-b, --backup 創(chuàng)建備份,也就是對(duì)于目的已經(jīng)存在有同樣的文件名時(shí),將老的文件重新命名為~filename。可以使用--suffix選項(xiàng)來指定不同的備份文件前綴。
--backup-dir 將備份文件(如~filename)存放在在目錄下。
-suffix=SUFFIX 定義備份文件前綴
-u, --update 僅僅進(jìn)行更新,也就是跳過所有已經(jīng)存在于DST,并且文件時(shí)間晚于要備份的文件。(不覆蓋更新的文件)
-l, --links 保留軟鏈結(jié)
-L, --copy-links 想對(duì)待常規(guī)文件一樣處理軟鏈結(jié)
--copy-unsafe-links 僅僅拷貝指向SRC路徑目錄樹以外的鏈結(jié)
--safe-links 忽略指向SRC路徑目錄樹以外的鏈結(jié)
-H, --hard-links 保留硬鏈結(jié) -p, --perms 保持文件權(quán)限
-o, --owner 保持文件屬主信息 -g, --group 保持文件屬組信息
-D, --devices 保持設(shè)備文件信息 -t, --times 保持文件時(shí)間信息
-S, --sparse 對(duì)稀疏文件進(jìn)行特殊處理以節(jié)省DST的空間
-n, --dry-run現(xiàn)實(shí)哪些文件將被傳輸
-W, --whole-file 拷貝文件,不進(jìn)行增量檢測(cè)
-x, --one-file-system 不要跨越文件系統(tǒng)邊界
-B, --block-size=SIZE 檢驗(yàn)算法使用的塊尺寸,默認(rèn)是700字節(jié)
-e, --rsh=COMMAND 指定使用rsh、ssh方式進(jìn)行數(shù)據(jù)同步
--rsync-path=PATH 指定遠(yuǎn)程服務(wù)器上的rsync命令所在路徑信息
-C, --cvs-exclude 使用和CVS一樣的方法自動(dòng)忽略文件,用來排除那些不希望傳輸?shù)奈募?br />
--existing 僅僅更新那些已經(jīng)存在于DST的文件,而不備份那些新創(chuàng)建的文件
--delete 刪除那些DST中SRC沒有的文件
--delete-excluded 同樣刪除接收端那些被該選項(xiàng)指定排除的文件
--delete-after 傳輸結(jié)束以后再刪除
--ignore-errors 及時(shí)出現(xiàn)IO錯(cuò)誤也進(jìn)行刪除
--max-delete=NUM 最多刪除NUM個(gè)文件
--partial 保留那些因故沒有完全傳輸?shù)奈募允羌涌祀S后的再次傳輸
--force 強(qiáng)制刪除目錄,即使不為空
--numeric-ids 不將數(shù)字的用戶和組ID匹配為用戶名和組名
--timeout=TIME IP超時(shí)時(shí)間,單位為秒
-I, --ignore-times 不跳過那些有同樣的時(shí)間和長度的文件
--size-only 當(dāng)決定是否要備份文件時(shí),僅僅察看文件大小而不考慮文件時(shí)間
--modify-window=NUM 決定文件是否時(shí)間相同時(shí)使用的時(shí)間戳窗口,默認(rèn)為0
-T --temp-dir=DIR 在DIR中創(chuàng)建臨時(shí)文件
--compare-dest=DIR 同樣比較DIR中的文件來決定是否需要備份
-P 等同于 --partial
--progress 顯示備份過程
-z, --compress 對(duì)備份的文件在傳輸時(shí)進(jìn)行壓縮處理
--exclude=PATTERN 指定排除不需要傳輸?shù)奈募J?br />
--include=PATTERN 指定不排除而需要傳輸?shù)奈募J?br />
--exclude-from=FILE 排除FILE中指定模式的文件
--include-from=FILE 不排除FILE指定模式匹配的文件
--version 打印版本信息
--address 綁定到特定的地址
--config=FILE 指定其他的配置文件,不使用默認(rèn)的rsyncd.conf文件
--port=PORT 指定其他的rsync服務(wù)端口
--blocking-io 對(duì)遠(yuǎn)程shell使用阻塞IO
-stats 給出某些文件的傳輸狀態(tài)
--progress 在傳輸時(shí)現(xiàn)實(shí)傳輸過程
--log-format=formAT 指定日志文件格式
--password-file=FILE 從FILE中得到密碼
--bwlimit=KBPS 限制I/O帶寬,KBytes per second -h, --help 顯示幫助信息
Collection接口 由 Set接口 和 List接口 繼承。
Set 被 Vector . ArrayList LinkedList 實(shí)現(xiàn)。
List 被 HashSet TreeSet 實(shí)現(xiàn)。
Map接口 由 HashTable HashMap TreeMap 實(shí)現(xiàn)。
下面看下每個(gè)實(shí)現(xiàn)類的特征;;;--》(轉(zhuǎn)的。)
1. List (有重復(fù)、有序)
Vector基于Array的List,性能也就不可能超越Array,并且Vector是“sychronized”的,這個(gè)也是Vector和ArrayList的唯一的區(qū)別。
ArrayList:同Vector一樣是一個(gè)基于Array的,但是不同的是ArrayList不是同步的。所以在性能上要比Vector優(yōu)越一些,但是當(dāng)運(yùn)行到多線程環(huán)境中時(shí),可需要自己在管理線程的同步問題。從其命名中可以看出它是一種類似數(shù)組的形式進(jìn)行存儲(chǔ),因此它的隨機(jī)訪問速度極快。
數(shù)據(jù)增長:當(dāng)需要增長時(shí),Vector默認(rèn)增長為原來一培,而ArrayList卻是原來的一半
LinkedList:LinkedList不同于前面兩種List,它不是基于Array的,所以不受Array性能的限制。它每一個(gè)節(jié)點(diǎn)(Node)都包含兩方面的內(nèi)容:1.節(jié)點(diǎn)本身的數(shù)據(jù)(data);2.下一個(gè)節(jié)點(diǎn)的信息(nextNode)。所以當(dāng)對(duì)LinkedList做添加,刪除動(dòng)作的時(shí)候就不用像基于Array的List一樣,必須進(jìn)行大量的數(shù)據(jù)移動(dòng)。只要更改nextNode的相關(guān)信息就可以實(shí)現(xiàn)了所以它適合于進(jìn)行頻繁進(jìn)行插入和刪除操作。這就是LinkedList的優(yōu)勢(shì)。Iterator只能對(duì)容器進(jìn)行向前遍歷,而 ListIterator則繼承了Iterator的思想,并提供了對(duì)List進(jìn)行雙向遍歷的方法。
用在FIFO,用addList()加入元素 removeFirst()刪除元素
用在FILO,用addFirst()/removeLast()
ListIterator 提供雙向遍歷next() previous(),可刪除、替換、增加元素
List總結(jié): 1. 所有的List中只能容納單個(gè)不同類型的對(duì)象組成的表,而不是Key-Value鍵值對(duì)。例如:[ tom,1,c ]; 2. 所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ]; 3. 所有的List中可以有null元素,例如[ tom,null,1 ]; 4. 基于Array的List(Vector,ArrayList)適合查詢,而LinkedList(鏈表)適合添加,刪除操作。
2. Set
HashSet:雖然Set同List都實(shí)現(xiàn)了Collection接口,但是他們的實(shí)現(xiàn)方式卻大不一樣。List基本上都是以Array為基礎(chǔ)。但是Set則是在HashMap的基礎(chǔ)上來實(shí)現(xiàn)的,這個(gè)就是Set和List的根本區(qū)別。HashSet的存儲(chǔ)方式是把HashMap中的Key作為Set的對(duì)應(yīng)存儲(chǔ)項(xiàng),這也是為什么在Set中不能像在List中一樣有重復(fù)的項(xiàng)的根本原因,因?yàn)镠ashMap的key是不能有重復(fù)的。HashSet能快速定位一個(gè)元素,但是放到HashSet中的對(duì)象需要實(shí)現(xiàn)hashCode()方法0。
TreeSet則將放入其中的元素按序存放,這就要求你放入其中的對(duì)象是可排序的,這就用到了集合框架提供的另外兩個(gè)實(shí)用類Comparable和Comparator。一個(gè)類是可排序的,它就應(yīng)該實(shí)現(xiàn)Comparable接口。有時(shí)多個(gè)類具有相同的排序算法,那就不需要重復(fù)定義相同的排序算法,只要實(shí)現(xiàn)Comparator接口即可。TreeSet是SortedSet的子類,它不同于HashSet的根本就是TreeSet是有序的。它是通過SortedMap來實(shí)現(xiàn)的。
Set總結(jié): 1. Set實(shí)現(xiàn)的基礎(chǔ)是Map(HashMap); 2. Set中的元素是不能重復(fù)的,如果使用add(Object obj)方法添加已經(jīng)存在的對(duì)象,則會(huì)覆蓋前面的對(duì)象; Set里的元素是不能重復(fù)的,那么用什么方法來區(qū)分重復(fù)與否呢? 是用==還是equals()? 它們有何區(qū)別? Set里的元素是不能重復(fù)的,即不能包含兩個(gè)元素e1、e2(e1.equals(e2))。那么用iterator()方法來區(qū)分重復(fù)與否。equals()是判讀兩個(gè)Set是否相等。==方法決定引用值(句柄)是否指向同一對(duì)象。
3. Map
Map是一種把鍵對(duì)象和值對(duì)象進(jìn)行關(guān)聯(lián)的容器,Map有兩種比較常用的實(shí)現(xiàn): HashTable、HashMap和TreeMap。
HashMap也用到了哈希碼的算法,以便快速查找一個(gè)鍵,TreeMap則是對(duì)鍵按序存放,因此它有一些擴(kuò)展的方法,比如firstKey(),lastKey()等。
只有HashMap可以讓你將空值作為一個(gè)表的條目的key或value
HashMap和Hashtable的區(qū)別。 HashMap是Hashtable的輕量級(jí)實(shí)現(xiàn)(非線程安全的實(shí)現(xiàn)),他們都完成了Map接口。主要區(qū)別在于HashMap允許空(null)鍵(key)或值(value),非同步,由于非線程安全,效率上可能高于Hashtable。 Hashtable不允許空(null)鍵(key)或值(value),Hashtable的方法是Synchronize的,在多個(gè)線程訪問Hashtable時(shí),不需要自己為它的方法實(shí)現(xiàn)同步,而HashMap 就必須為之提供外同步。 Hashtable和HashMap采用的hash/rehash算法都大概一樣,所以性能不會(huì)有很大的差異。
HashMap:
散列表的通用映射表,無序,可在初始化時(shí)設(shè)定其大小,自動(dòng)增長。
只有HashMap可以讓你將空值作為一個(gè)表的條目的key或value
LinkedHashMap:
擴(kuò)展HashMap,對(duì)返回集合迭代時(shí),維護(hù)插入順序
WeakHashMap:
基于弱引用散列表的映射表,如果不保持映射表外的關(guān)鍵字的引用,則內(nèi)存回收程序會(huì)回收它
TreeMap:
基于平衡樹的映射表