2011年5月8日

          前兩天休眠后機器非正常關(guān)機,重新啟動后運行eclipse。悲催的發(fā)現(xiàn)eclipse 無法啟動了。每次雙擊啟動后,確定完workspace后,顯示啟動畫面,沒過一會就進入灰色無響應(yīng)狀態(tài)。啟動畫面始終停留在Loading workbench狀態(tài)。反復(fù)重啟,狀態(tài)依舊。嘗試解決。

          搜索了一下,應(yīng)該是非正常關(guān)機導(dǎo)致eclipse工作區(qū)的文件狀態(tài)錯誤導(dǎo)致。在工作區(qū)目錄中,有一個.metadata目錄,里面是工作區(qū)及各插件的信息,刪除此目錄可以解決問題。

          為保險起見,將.metadata改名移動到/tmp目錄,再重啟eclipse,果然可以正常啟動eclipse了,但原來工作區(qū)的配置和項目信息也都消失,直接顯示的是歡迎界面。

          如何恢復(fù)原來的project配置呢?嘗試對比了當(dāng)前的.metadata和之前備份的那個目錄,發(fā)現(xiàn)缺少了很多配置文件。試著一點點恢復(fù)一些目錄,但效 果不理想。因為不知道哪些文件(目錄)可以恢復(fù),哪些恢復(fù)會帶來問題。將備份的整個目錄恢復(fù)試試?Eclipse又回到了無法啟動的狀態(tài)了。

          怎么辦?這時想到啟動停止時顯示的狀態(tài):"Loading workbench",看來和這個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)了兩個: org.eclipse.ui.workbenchorg.eclipse.ui.workbench.texteditor

          不管三七二十一,刪了這兩個目錄,重新啟動eclipse。正常啟動且原項目信息正確加載。
          posted @ 2012-11-11 14:15 胡鵬 閱讀(6458) | 評論 (7)編輯 收藏

          最近團隊遇到一個案例。看似很小的事情,但仔細研究起來,徹底分析,每一個環(huán)節(jié)都沒做好,細節(jié)部分糟糕得一塌糊涂,最后導(dǎo)致一件事情的結(jié)果:完全失敗。

          經(jīng)常有人在聊起公司的時候問我,你現(xiàn)在最擔(dān)心的事情有哪些? 我當(dāng)然會重點提到團隊。不過在談及團隊的時候,我又最擔(dān)心在「細節(jié)」問題上做不好。

          細節(jié)就是競爭力,尤其是對小團隊來說,小團隊更應(yīng)該注重細節(jié)問題。大一點的公司可以追究責(zé)任人,靠流程、靠制度,靠各級評審等等一系列的「成本」來提升細節(jié)能力。小一點的公司或者團隊怎么辦? 恐怕只有依賴每個人的能力和責(zé)任心了。

          細節(jié)也是鍛煉人的能力的地方,搞清楚每一個細節(jié),將每一個細節(jié)涉及到的背景知識和技能掌握好,能力自然也就會得到提升。繼而,著手做更大的事情也不 會手忙腳亂。相反,做不好細節(jié)和小事的人,如果總?cè)轮觥钢匾沟氖虑椋龈小柑魬?zhàn)」的事情,這樣的事情真的到你面前,真的能接住么?

          為什么我們在細節(jié)上做不好?

          對細節(jié)問題不夠重視 一件事情到了自己這里,頭腦中先入為主認為只是一件小事,是一件簡單的事情。這樣,當(dāng)然就不會給予足夠的重視。小事不一定不重要,小事不一定意味著做起來就簡單。

          對事情復(fù)雜度缺乏認知 不就是給客戶寫一封電子郵件么? 不就是用 HTML 寫一個頁面么? 不就是做一則橫幅廣告么? 那么,這些事情真的簡單么? 為什么別人為客戶寫的郵件打開率更高? 為什么別人寫的頁面更容易被搜索引擎收錄? 為什么別人做的廣告轉(zhuǎn)化率更好? 背后涉及到哪些知識? 不想研究一下么? 不能研究一下么?

          對細節(jié)缺乏耐心 草草了事,應(yīng)付了事,遇到問題馬馬虎虎,輕易得放過了很多可以讓自己得到成長的機會。「這問題我沒想過」「這事情我沒遇到過」「設(shè)計稿都改過兩次了」... 這類借口在任何一個團隊都很常見。

          缺少責(zé)任心 常常覺得自己這里做不好,還有別人會把關(guān)呢。擔(dān)心什么? 可如果所有人都這么想呢? 「文案是產(chǎn)品經(jīng)理的事情,關(guān)我甚么事?」如果你能對文案也有改進意見,誰說以后你就不能做產(chǎn)品經(jīng)理做的事情呢?

          主觀上不認可自己的工作 就給我這么一點錢,要我做這么多工作? 問題是我們?nèi)绻欢嘧鲆稽c工作,不提升一下自己,又怎么能多一點錢呢?

          為什么細節(jié)上做不好? 不同人不同的角度還會有不同的看法。不過有一點我能肯定,細節(jié)不會決定成敗,但做不好細節(jié),一定會失敗。

          做好細節(jié),百事可作。

          posted @ 2012-10-28 16:31 胡鵬 閱讀(239) | 評論 (0)編輯 收藏
          mac中自帶的jdk并不包含源代碼,所以在eclipse中無法查看, 需要到apple上去下載,
          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
          下載下來后,直接安裝,默認設(shè)置就可以了,然后可以建個link,方便選擇。
          1. sudo -s
          2. cd /System/Library/Frameworks/JavaVM.framework/Home
          3. ln -s /Library/Java/JavaVirtualMachines/1.6.0_35-b10-428.jdk/Contents/Home/docs.jar
          4. ln -s  /Library/Java/JavaVirtualMachines/1.6.0_35-b10-428.jdk/Contents/Home/src.jar
          5. 最后跟windows類似,在eclipse中用command + click點擊查看一個類的源碼。然后選“add source",選中上面的 src.jar 文件即可
          posted @ 2012-10-16 21:48 胡鵬 閱讀(3791) | 評論 (0)編輯 收藏
          雖然android安裝完成后會有一套參考手冊,其中包括了api,但是如果在開發(fā)過程中能查看android的源碼(sdk的源碼),將對我們學(xué)習(xí)android有一定的幫助.畢竟,有時候源碼比api文檔更能說明問題.
              我平常學(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)放在一個android提供的類上,按下ctrl鍵,會打開一個新頁面,提示 找不到對應(yīng)的類的class或者源文件,但這個新頁面上有個導(dǎo)入源碼的按鈕,點擊之后選擇下載好的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

          posted @ 2012-09-16 10:15 胡鵬 閱讀(459) | 評論 (0)編輯 收藏
                  離開淘寶后,自己創(chuàng)業(yè),產(chǎn)品需要推廣,考慮到當(dāng)今流量最大的聚集在微博上,我們也來做做微博運營,我是一個技術(shù)人員,運營對于我來說,從0開始,站在巨人的肩膀上學(xué)習(xí),稍稍總結(jié)了下。

          1. 使用工具:微博第三方插件已經(jīng)提供了很多功能,適合自己的都用起來,這個我覺得最節(jié)省我的時間,其他網(wǎng)上提供的軟件都可以使用,重要是適合自己,安全第一。

          2. 寫工具:有很多個性化需求的時候,如果變相的不能實現(xiàn),人為處理太慢太花時間,我們現(xiàn)在是小創(chuàng)業(yè)團隊,很多事情都需要自己做,數(shù)據(jù)增長慢,在有限的資源下,寫工具是非常好的方式,作為技術(shù)人員就直接動手寫,當(dāng)然也需要看看性價比。


          3.微博定位:
          找好本微博的主題,內(nèi)容一般遵循原則:定制+非定制。定制是指針對你的目標(biāo)群體來選擇內(nèi)容,要讓這部分人感興趣,非定制:是指那種適合任何粉絲的內(nèi)容。

           

          例如:我的目標(biāo)群體是女性,我的定制內(nèi)容就有美容、護膚、服飾搭配、星座、愛情等女性關(guān)注的話題,非定制的有笑話、經(jīng)典語錄、旅游等大眾類容。根據(jù)內(nèi)容來 建立話題,如#美容護膚# #開心一笑##XX語錄#等等,我就為自己建立了10個左右話題,每天的內(nèi)容按照話題來制作。

           

          4.主要工作流程:(這個圖是轉(zhuǎn)的)


          5.常用的微博話題(這個圖片也是轉(zhuǎn)的)



          6. 關(guān)注項目:微博和主動@,評論,私信,群,邀請,勛章,策劃產(chǎn)品活動,參與微活動

           

           7.微博運營最重要的是:一段時間需要總結(jié)挑選合適的方法執(zhí)行,沒有效果的去除。

          如:微博發(fā)布時間/數(shù)量

          我(轉(zhuǎn),不是我)曾在粉絲超過一萬之后就開始研究的我的微博改什么時候發(fā)布,每天發(fā)布多少。我現(xiàn)在粉絲中做了一個投票:你們一般什么時候織微博。最后有200多人參加, 我大概劃分了5個時段,9-12點,12-17點 17-19點 19-22點 22-24點 0-3點,做多選擇3個答案,結(jié)果出來之后就有個大概了。接下來我用一周的時間從9點—24點之間每1小時發(fā)布一條信息。總共16條信息,我就分析每條信 息的轉(zhuǎn)發(fā)、回復(fù)數(shù)量,一周之后我就可以摸清粉絲的上網(wǎng)時間規(guī)律。然后我選擇哪幾個時間段重點維護,并在那幾個時間段進一步研究發(fā)布數(shù)量規(guī)律,我又分為每1小時,每0.5小時兩個因素來研究發(fā)布數(shù)量。



                
          posted @ 2012-03-28 18:28 胡鵬 閱讀(255) | 評論 (0)編輯 收藏

          JMock是幫助創(chuàng)建mock對象的工具,它基于Java開發(fā),在Java測試與開發(fā)環(huán)境中有不可比擬的優(yōu)勢,更重要的是,它大大簡化了虛擬對象的使用。本文中,通過一個簡單的測試用例來說明JMock如何幫助我們實現(xiàn)這種孤立測試。
              我們在測試某類時,由于它要與其他類發(fā)生聯(lián)系,因此往往在測試此類的代碼中也將與之聯(lián)系的類也一起測試了。這種測試,將使被測試的類直接依賴于其他類,一旦其他類發(fā)生改變,被測試類也隨之被迫改變。更重要的是,這些其他類可能尚未經(jīng)過測試,因此必須先測試這些類,才能測試被測試類。這種情況下,測試驅(qū)動開發(fā)成為空談。而如果其他類中也引用了被測試類,我們到底先測試哪一個類?因此,在測試中,如果我們能將被測試類孤立起來,使其完全不依賴于其他類的具體實現(xiàn),這樣,我們就能做到測試先行,先測試哪個類,就先實現(xiàn)哪個類,而不管與之聯(lián)系的類是否已經(jīng)實現(xiàn)。

              虛擬對象(mock object)就是為此需要而誕生的。它通過JDK中的反射機制,在運行時動態(tài)地創(chuàng)建虛擬對象。在測試代碼中,我們可以驗證這些虛擬對象是否被正確地調(diào)用了,也可以在明確的情況下,讓其返回特定的假想值。而一旦有了這些虛擬對象提供的服務(wù),被測試類就可以將虛擬對象作為其他與之聯(lián)系的真實對象的替身,從而輕松地搭建起一個很完美的測試環(huán)境。

              JMock是幫助創(chuàng)建mock對象的工具,它基于Java開發(fā),在Java測試與開發(fā)環(huán)境中有不可比擬的優(yōu)勢,更重要的是,它大大簡化了虛擬對象的使用。

              本文中,通過一個簡單的測試用例來說明JMock如何幫助我們實現(xiàn)這種孤立測試。有三個主要的類,User,UserDAO,及UserService。本文中,我們只需測試UserService,準(zhǔn)備虛擬UserDAO。對于User,由于本身僅是一個過于簡單的POJO,可以不用測試。但如果你是一個完美主義者,也可以使用JMock的虛擬它。在這領(lǐng)域,JMock幾乎無所不能。

          這里我用到的是:(我用的是maven依賴)

                      <dependency>
             <groupId>org.jmock</groupId>
             <artifactId>jmock</artifactId>
             <version>2.5.1</version>
          </dependency>
           
          <dependency>
             <groupId>org.jmock</groupId>
             <artifactId>jmock-junit3</artifactId>
             <version>2.5.1</version>
          </dependency>

          在官方的網(wǎng)站上也有的下載。   地址:  http://jmock.org/dist/jmock-2.5.1-jars.zip

           


          public class User {
          private String name;
          public User() {
          }
          public User(String name) {
          this.name = name;
          }
          public String getName() {
          return name;
          }
          public void setName(String name) {
          this.name = name;
          }
          }

           UserDAO負責(zé)與數(shù)據(jù)庫打交道,通過數(shù)據(jù)庫保存、獲取User的信息。盡管我們可以不用知道JMock如何通過JDK 的反射機制來實現(xiàn)孤立測試,但至少應(yīng)知道,JDK的反射機制要求這些在運行時創(chuàng)建的動態(tài)類必須定義接口。在使用JMock的環(huán)境中,由于我們要虛擬 UserDAO,意味著UserDAO必須定義接口

          public interface UserDAO {
          public User getUser(Long id);
          }

          public interface UserService {
          public void setUserDAO(UserDAO userDAO);
          public User getUser(Long id);
          }



          public class UserServiceImpl implements UserService {
          private UserDAO userDAO;
          public UserServiceImpl() {
          }
          public void setUserDAO(UserDAO userDAO) {
          this.userDAO = userDAO;
          }
          public User getUser(Long id) {
          return userDAO.getUser(id);
          }
          }


           
          import org.jmock.Expectations;
          import org.jmock.integration.junit3.MockObjectTestCase;

          public class UserServiceTest extends MockObjectTestCase {
          private UserService userService = new UserServiceImpl();
          private UserDAO userDAO = null;
          public UserServiceTest(String testName) {
          super(testName);
          }
          protected void setUp() throws Exception {
          userDAO = mock(UserDAO.class);
          userService.setUserDAO(userDAO);
          }
          public void testGetUser() {
          String name = "lsb";
          final User fakeUser = new User(name);
          checking(new Expectations(){{
                      oneOf(userDAO).getUser(1L);
                      will(returnValue(fakeUser));
                  }});
          User user = userService.getUser(1L);
          assertNotNull(user);
          assertEquals(name, user.getName());
          }
          protected void tearDown() throws Exception {
          }
          }

          posted @ 2012-02-23 21:52 胡鵬 閱讀(865) | 評論 (0)編輯 收藏
                   在開發(fā)Android和iPhone應(yīng)用程序時,我們往往需要從服務(wù)器不定的向手 機客戶端即時推送各種通知消息,iPhone上已經(jīng)有了比較簡單的和完美的推送通知解決方案,可是Android平臺上實現(xiàn)起來卻相對比較麻煩,最近利用 幾天的時間對Android的推送通知服務(wù)進行初步的研究。
          在Android手機平臺上,Google提供了C2DM(Cloudto Device Messaging)服務(wù)。

          Android Cloud to Device Messaging (C2DM)是一個用來幫助開發(fā)者從服務(wù)器向Android應(yīng)用程序發(fā)送數(shù)據(jù)的服務(wù)。該服務(wù)提供了一個簡單的、輕量級的機制,允許服務(wù)器可以通知移動應(yīng)用程序直接與服務(wù)器進行通信,以便于從服務(wù)器獲取應(yīng)用程序更新和用戶數(shù)據(jù)。C2DM服務(wù)負責(zé)處理諸如消息排隊等事務(wù)并向運行于目標(biāo)設(shè)備上的應(yīng)用程序分發(fā)這些消息。

          使用C2DM框架的要求
          1. 需要Android2.2及以上的系統(tǒng)版本
          2. 使用C2DM功能的Android設(shè)備上需要設(shè)置好Google的賬戶。
          3.  C2DM需要依賴于Google官方提供的C2DM服務(wù)器,由于國內(nèi)的網(wǎng)絡(luò)環(huán)境,這個服務(wù)經(jīng)常不可用,如果想要很好的使用,我們的App Server必須也在國外,這個恐怕不是每個開發(fā)者都能夠?qū)崿F(xiàn)的

          要使用C2DM來進行Push操作,基本上要使用以下6個步驟


          (1)注冊:Android設(shè)備把使用C2DM功能的用戶賬戶(比如android.c2dm.demo@gmail.com)和App名稱發(fā)送給C2DM服務(wù)器。

          (2)C2DM服務(wù)器會返回一個registration_id值給Android設(shè)備,設(shè)備需要保存這個registration_id值。

          (3)Android設(shè)備把獲得的registration_id和C2DM功能的用戶賬戶(android.c2dm.demo@gmail.com)發(fā)送給自己的服務(wù)器,不過一般用戶賬戶信息因為和服務(wù)器確定好的,所以不必發(fā)送。

          這樣Android設(shè)備就完成了C2DM功能的注冊過程,接下來就可以接收C2DM服務(wù)器Push過來的消息了。

          (4)服務(wù)器獲得數(shù)據(jù)。這里圖中的例子Chrome To Phone,服務(wù)器接收到Chrome瀏覽器發(fā)送的數(shù)據(jù)。數(shù)據(jù)也可以是服務(wù)器本地產(chǎn)生的。這里的服務(wù)器是Google AppEngine(很好的一項服務(wù),可惜在國內(nèi)被屏了),要換成自己的服務(wù)器。服務(wù)器還要獲取注冊使用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ù)器會以Push的方式把數(shù)據(jù)發(fā)送給對應(yīng)的Android設(shè)備,Android設(shè)備只要在程序中按之前和服務(wù)器商量好的格式從對應(yīng)的key中獲取數(shù)據(jù)即可。

          轉(zhuǎn)自:
          posted @ 2011-12-29 17:57 胡鵬 閱讀(1168) | 評論 (0)編輯 收藏

          地理位置索引支持是MongoDB的一大亮點,這也是全球最流行的LBS服務(wù)foursquare 選擇MongoDB的原因之一。我們知道,通常的數(shù)據(jù)庫索引結(jié)構(gòu)是B+ Tree,如何將地理位置轉(zhuǎn)化為可建立B+Tree的形式,下文將為你描述。

          首先假設(shè)我們將需要索引的整個地圖分成16×16的方格,如下圖(左下角為坐標(biāo)0,0 右上角為坐標(biāo)16,16):

           

          單純的[x,y]的數(shù)據(jù)是無法建立索引的,所以MongoDB在建立索引的時候,會根據(jù)相應(yīng)字段的坐標(biāo)計算一個可以用來做索引的hash值,這個值叫做geohash,下面我們以地圖上坐標(biāo)為[4,6]的點(圖中紅叉位置)為例。

          我們第一步將整個地圖分成等大小的四塊,如下圖:



          劃分成四塊后我們可以定義這四塊的值,如下(左下為00,左上為01,右下為10,右上為11):

          01 11
          00 10

          這樣[4,6]點的geohash值目前為 00

          然后再將四個小塊每一塊進行切割,如下:



          這時[4,6]點位于右上區(qū)域,右上的值為11,這樣[4,6]點的geohash值變?yōu)椋?011

          繼續(xù)往下做兩次切分:




          最終得到[4,6]點的geohash值為:00110100

          這樣我們用這個值來做索引,則地圖上點相近的點就可以轉(zhuǎn)化成有相同前綴的geohash值了。

          我們可以看到,這個geohash值的精確度是與劃分地圖的次數(shù)成正比的,上例對地圖劃分了四次。而MongoDB默認是進行26次劃分,這個值在建立索引時是可控的。具體建立二維地理位置索引的命令如下:

          db.map.ensureIndex({point : "2d"}, {min : 0, max : 16, bits : 4})

          其中的bits參數(shù)就是劃分幾次,默認為26次。










           

          posted @ 2011-11-25 17:19 胡鵬 閱讀(577) | 評論 (0)編輯 收藏
               摘要: java中的引用分為4種:String Reference, WeakReference, softReference,PhantomReference  Strong Reference: 我們平常用的最多的就是強引用了 如:String s = new String("opps");這種形式的引用稱為強引用,這種引用有以下幾個特點 1.強引用可以直接訪問目標(biāo)對象&...  閱讀全文
          posted @ 2011-10-30 11:59 胡鵬 閱讀(1102) | 評論 (0)編輯 收藏
               摘要:   一、對ThreadLocal概術(shù)             JDK API 寫道: 該類提供了線程局部 (thread-local) 變量。這些變量不同于它們的普通對應(yīng)物,因為訪問某個變量(通過其 get 或 set 方法)的每個線程都有自己的局部變量,它獨立于變量的初始...  閱讀全文
          posted @ 2011-10-29 17:39 胡鵬 閱讀(1446) | 評論 (0)編輯 收藏
               摘要:        起因:在寫java的時候,經(jīng)常遇到函數(shù)需要返回2個值或者3個值,java必須編寫一個Object,來封裝,但很多應(yīng)用場景只是臨時使用,構(gòu)建對象感覺殺雞用宰牛刀,而其他語言有比較好的實現(xiàn)方法。(當(dāng)然通過指針引用可以解決一部分問題) 如:一般寫法:     Code high...  閱讀全文
          posted @ 2011-10-28 18:35 胡鵬 閱讀(6406) | 評論 (0)編輯 收藏
               摘要:     java.util.concurrent包分成了三個部分,分別是:                        ...  閱讀全文
          posted @ 2011-10-12 17:25 胡鵬 閱讀(2444) | 評論 (0)編輯 收藏
                不復(fù)制內(nèi)容了,可以看戲如下鏈接,還是有很多值得看的東東,有空看下。~

              
              http://terryblog.blog.51cto.com/1764499/547777
          posted @ 2011-07-13 20:12 胡鵬 閱讀(254) | 評論 (0)編輯 收藏


          申請一個Android Maps API Key

          1.找到你的debug.keystore文件所在的路徑:
          證書的一般路徑為:打開eclipse,選擇Windows———>Preference———>Android———>Build,其中Default debug  keystore的值便是debug.keystore的路徑(windows的一般在 C:\Documents and Settings\當(dāng)前用戶\.android下找到debug.keystore)
          2.在命令提示符中執(zhí)行: keytool -list -keystore debug.keystore  (keytool是java一個命令,在%java_home%\bin里可以看到)
          需要輸入密碼:android
          然后就會得到MD5的值,進入
          http://code.google.com/intl/zh-CN/android/add-ons/google-apis/maps-api-signup.html ,根據(jù)MD5值獲取MAPS API KEY(前提是你必須有一個google賬戶)
          posted @ 2011-06-18 16:37 胡鵬 閱讀(998) | 評論 (0)編輯 收藏
                使input組件的絕對位置覆蓋select組件的選擇框,當(dāng)select的狀態(tài)發(fā)生改變的時候,使用this.parentNode.nextSibling.value=this.value把select所選擇的值賦給input.

          <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)建模式是一個通用的編程習(xí)語。和多線程一起使用時,必需使用某種類型的同步。在努力創(chuàng)建更有效的代碼時,Java 程序員們創(chuàng)建了雙重檢查鎖定習(xí)語,將其和單例創(chuàng)建模式一起使用,從而限制同步代碼量。然而,由于一些不太常見的 Java 內(nèi)存模型細節(jié)的原因,并不能保證這個雙重檢查鎖定習(xí)語有效。它偶爾會失敗,而不是總失敗。此外,它失敗的原因并不明顯,還包含 Java 內(nèi)存模型的一些隱秘細節(jié)。這些事實將導(dǎo)致代碼失敗,原因是雙重檢查鎖定難于跟蹤。在本文余下的部分里,我們將詳細介紹雙重檢查鎖定習(xí)語,從而理解它在何處失效。

          單例創(chuàng)建習(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è)計確保只創(chuàng)建一個 Singleton 對象。構(gòu)造函數(shù)被聲明為 privategetInstance() 方法只創(chuàng)建一個對象。這個實現(xiàn)適合于單線程程序。然而,當(dāng)引入多線程時,就必須通過同步來保護 getInstance() 方法。如果不保護 getInstance() 方法,則可能返回 Singleton 對象的兩個不同的實例。假設(shè)兩個線程并發(fā)調(diào)用 getInstance() 方法并且按以下順序執(zhí)行調(diào)用:

          1. 線程 1 調(diào)用 getInstance() 方法并決定 instance 在 //1 處為 null

          2. 線程 1 進入 if 代碼塊,但在執(zhí)行 //2 處的代碼行時被線程 2 預(yù)占。

          3. 線程 2 調(diào)用 getInstance() 方法并在 //1 處決定 instancenull

          4. 線程 2 進入 if 代碼塊并創(chuàng)建一個新的 Singleton 對象并在 //2 處將變量 instance 分配給這個新對象。

          5. 線程 2 在 //3 處返回 Singleton 對象引用。

          6. 線程 2 被線程 1 預(yù)占。

          7. 線程 1 在它停止的地方啟動,并執(zhí)行 //2 代碼行,這導(dǎo)致創(chuàng)建另一個 Singleton 對象。

          8. 線程 1 在 //3 處返回這個對象。

          結(jié)果是 getInstance() 方法創(chuàng)建了兩個 Singleton 對象,而它本該只創(chuàng)建一個對象。通過同步 getInstance() 方法從而在同一時間只允許一個線程執(zhí)行代碼,這個問題得以改正,如清單 2 所示:


          清單 2. 線程安全的 getInstance() 方法
                                  public static synchronized Singleton getInstance()
                      {
                      if (instance == null)          //1
                      instance = new Singleton();  //2
                      return instance;               //3
                      }
                      

          清單 2 中的代碼針對多線程訪問 getInstance() 方法運行得很好。然而,當(dāng)分析這段代碼時,您會意識到只有在第一次調(diào)用方法時才需要同步。由于只有第一次調(diào)用執(zhí)行了 //2 處的代碼,而只有此行代碼需要同步,因此就無需對后續(xù)調(diào)用使用同步。所有其他調(diào)用用于決定 instance 是非 null 的,并將其返回。多線程能夠安全并發(fā)地執(zhí)行除第一次調(diào)用外的所有調(diào)用。盡管如此,由于該方法是 synchronized 的,需要為該方法的每一次調(diào)用付出同步的代價,即使只有第一次調(diào)用需要同步。

          為使此方法更為有效,一個被稱為雙重檢查鎖定的習(xí)語就應(yīng)運而生了。這個想法是為了避免對除第一次調(diào)用外的所有調(diào)用都實行同步的昂貴代價。同步的代價在不同的 JVM 間是不同的。在早期,代價相當(dāng)高。隨著更高級的 JVM 的出現(xiàn),同步的代價降低了,但出入 synchronized 方法或塊仍然有性能損失。不考慮 JVM 技術(shù)的進步,程序員們絕不想不必要地浪費處理時間。

          因為只有清單 2 中的 //2 行需要同步,我們可以只將其包裝到一個同步塊中,如清單 3 所示:


          清單 3. getInstance() 方法
                                  public static Singleton getInstance()
                      {
                      if (instance == null)
                      {
                      synchronized(Singleton.class) {
                      instance = new Singleton();
                      }
                      }
                      return instance;
                      }
                      

          清單 3 中的代碼展示了用多線程加以說明的和清單 1 相同的問題。當(dāng) instancenull 時,兩個線程可以并發(fā)地進入 if 語句內(nèi)部。然后,一個線程進入 synchronized 塊來初始化 instance,而另一個線程則被阻斷。當(dāng)?shù)谝粋€線程退出 synchronized 塊時,等待著的線程進入并創(chuàng)建另一個 Singleton 對象。注意:當(dāng)?shù)诙€線程進入 synchronized 塊時,它并沒有檢查 instance 是否非 null







          雙重檢查鎖定

          為處理清單 3 中的問題,我們需要對 instance 進行第二次檢查。這就是“雙重檢查鎖定”名稱的由來。將雙重檢查鎖定習(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)建兩個不同的 Singleton 對象成為不可能。假設(shè)有下列事件序列:

          1. 線程 1 進入 getInstance() 方法。

          2. 由于 instancenull,線程 1 在 //1 處進入 synchronized 塊。

          3. 線程 1 被線程 2 預(yù)占。

          4. 線程 2 進入 getInstance() 方法。

          5. 由于 instance 仍舊為 null,線程 2 試圖獲取 //1 處的鎖。然而,由于線程 1 持有該鎖,線程 2 在 //1 處阻塞。

          6. 線程 2 被線程 1 預(yù)占。

          7. 線程 1 執(zhí)行,由于在 //2 處實例仍舊為 null,線程 1 還創(chuàng)建一個 Singleton 對象并將其引用賦值給 instance

          8. 線程 1 退出 synchronized 塊并從 getInstance() 方法返回實例。

          9. 線程 1 被線程 2 預(yù)占。

          10. 線程 2 獲取 //1 處的鎖并檢查 instance 是否為 null

          11. 由于 instance 是非 null 的,并沒有創(chuàng)建第二個 Singleton 對象,由線程 1 創(chuàng)建的對象被返回。

          雙重檢查鎖定背后的理論是完美的。不幸地是,現(xiàn)實完全不同。雙重檢查鎖定的問題是:并不能保證它會在單處理器或多處理器計算機上順利運行。

          雙重檢查鎖定失敗的問題并不歸咎于 JVM 中的實現(xiàn) bug,而是歸咎于 Java 平臺內(nèi)存模型。內(nèi)存模型允許所謂的“無序?qū)懭?#8221;,這也是這些習(xí)語失敗的一個主要原因。







          無序?qū)懭?/span>

          為解釋該問題,需要重新考察上述清單 4 中的 //3 行。此行代碼創(chuàng)建了一個 Singleton 對象并初始化變量 instance 來引用此對象。這行代碼的問題是:在 Singleton 構(gòu)造函數(shù)體執(zhí)行之前,變量 instance 可能成為非 null 的。

          什么?這一說法可能讓您始料未及,但事實確實如此。在解釋這個現(xiàn)象如何發(fā)生前,請先暫時接受這一事實,我們先來考察一下雙重檢查鎖定是如何被破壞的。假設(shè)清單 4 中代碼執(zhí)行以下事件序列:

          1. 線程 1 進入 getInstance() 方法。

          2. 由于 instancenull,線程 1 在 //1 處進入 synchronized 塊。

          3. 線程 1 前進到 //3 處,但在構(gòu)造函數(shù)執(zhí)行之前,使實例成為非 null

          4. 線程 1 被線程 2 預(yù)占。

          5. 線程 2 檢查實例是否為 null。因為實例不為 null,線程 2 將 instance 引用返回給一個構(gòu)造完整但部分初始化了的 Singleton 對象。

          6. 線程 2 被線程 1 預(yù)占。

          7. 線程 1 通過運行 Singleton 對象的構(gòu)造函數(shù)并將引用返回給它,來完成對該對象的初始化。

          此事件序列發(fā)生在線程 2 返回一個尚未執(zhí)行構(gòu)造函數(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 編譯器上真實發(fā)生的。執(zhí)行的順序是顛倒的,但鑒于當(dāng)前的內(nèi)存模型,這也是允許發(fā)生的。JIT 編譯器的這一行為使雙重檢查鎖定的問題只不過是一次學(xué)術(shù)實踐而已。

          為說明這一情況,假設(shè)有清單 5 中的代碼。它包含一個剝離版的 getInstance() 方法。我已經(jīng)刪除了“雙重檢查性”以簡化我們對生成的匯編代碼(清單 6)的回顧。我們只關(guān)心 JIT 編譯器如何編譯 instance=new Singleton(); 代碼。此外,我提供了一個簡單的構(gòu)造函數(shù)來明確說明匯編代碼中該構(gòu)造函數(shù)的運行情況。


          清單 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
                      

          注: 為引用下列說明中的匯編代碼行,我將引用指令地址的最后兩個值,因為它們都以 054D20 開頭。例如,B5 代表 test eax,eax

          匯編代碼是通過運行一個在無限循環(huán)中調(diào)用 getInstance() 方法的測試程序來生成的。程序運行時,請運行 Microsoft Visual C++ 調(diào)試器并將其附到表示測試程序的 Java 進程中。然后,中斷執(zhí)行并找到表示該無限循環(huán)的匯編代碼。

          B0B5 處的前兩行匯編代碼將 instance 引用從內(nèi)存位置 049388C8 加載至 eax 中,并進行 null 檢查。這跟清單 5 中的 getInstance() 方法的第一行代碼相對應(yīng)。第一次調(diào)用此方法時,instancenull,代碼執(zhí)行到 B9BE 處的代碼為 Singleton 對象從堆中分配內(nèi)存,并將一個指向該塊內(nèi)存的指針存儲到 eax 中。下一行代碼,C3,獲取 eax 中的指針并將其存儲回內(nèi)存位置為 049388C8 的實例引用。結(jié)果是,instance 現(xiàn)在為非 null 并引用一個有效的 Singleton 對象。然而,此對象的構(gòu)造函數(shù)尚未運行,這恰是破壞雙重檢查鎖定的情況。然后,在 C8 行處,instance 指針被解除引用并存儲到 ecxCAD0 行表示內(nèi)聯(lián)的構(gòu)造函數(shù),該構(gòu)造函數(shù)將值 true5 存儲到 Singleton 對象。如果此代碼在執(zhí)行 C3 行后且在完成該構(gòu)造函數(shù)前被另一個線程中斷,則雙重檢查鎖定就會失敗。

          不是所有的 JIT 編譯器都生成如上代碼。一些生成了代碼,從而只在構(gòu)造函數(shù)執(zhí)行后使 instance 成為非 null。針對 Java 技術(shù)的 IBM SDK 1.3 版和 Sun JDK 1.3 都生成這樣的代碼。然而,這并不意味著應(yīng)該在這些實例中使用雙重檢查鎖定。該習(xí)語失敗還有一些其他原因。此外,您并不總能知道代碼會在哪些 JVM 上運行,而 JIT 編譯器總是會發(fā)生變化,從而生成破壞此習(xí)語的代碼。







          雙重檢查鎖定:獲取兩個

          考慮到當(dāng)前的雙重檢查鎖定不起作用,我加入了另一個版本的代碼,如清單 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)該意識到事情變得有點荒謬。請記住,創(chuàng)建雙重檢查鎖定是為了避免對簡單的三行 getInstance() 方法實現(xiàn)同步。清單 7 中的代碼變得難于控制。另外,該代碼沒有解決問題。仔細檢查可獲悉原因。

          此代碼試圖避免無序?qū)懭雴栴}。它試圖通過引入局部變量 inst 和第二個 synchronized 塊來解決這一問題。該理論實現(xiàn)如下:

          1. 線程 1 進入 getInstance() 方法。

          2. 由于 instancenull,線程 1 在 //1 處進入第一個 synchronized 塊。

          3. 局部變量 inst 獲取 instance 的值,該值在 //2 處為 null

          4. 由于 instnull,線程 1 在 //3 處進入第二個 synchronized 塊。

          5. 線程 1 然后開始執(zhí)行 //4 處的代碼,同時使 inst 為非 null,但在 Singleton 的構(gòu)造函數(shù)執(zhí)行前。(這就是我們剛才看到的無序?qū)懭雴栴}。)

          6. 線程 1 被線程 2 預(yù)占。

          7. 線程 2 進入 getInstance() 方法。

          8. 由于 instancenull,線程 2 試圖在 //1 處進入第一個 synchronized 塊。由于線程 1 目前持有此鎖,線程 2 被阻斷。

          9. 線程 1 然后完成 //4 處的執(zhí)行。

          10. 線程 1 然后將一個構(gòu)造完整的 Singleton 對象在 //5 處賦值給變量 instance,并退出這兩個 synchronized 塊。

          11. 線程 1 返回 instance

          12. 然后執(zhí)行線程 2 并在 //2 處將 instance 賦值給 inst

          13. 線程 2 發(fā)現(xiàn) instance 為非 null,將其返回。

          這里的關(guān)鍵行是 //5。此行應(yīng)該確保 instance 只為 null 或引用一個構(gòu)造完整的 Singleton 對象。該問題發(fā)生在理論和實際彼此背道而馳的情況下。

          由于當(dāng)前內(nèi)存模型的定義,清單 7 中的代碼無效。Java 語言規(guī)范(Java Language Specification,JLS)要求不能將 synchronized 塊中的代碼移出來。但是,并沒有說不能將 synchronized 塊外面的代碼移 synchronized 塊中。

          JIT 編譯器會在這里看到一個優(yōu)化的機會。此優(yōu)化會刪除 //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;
                      }
                      

          如果進行此項優(yōu)化,您將同樣遇到我們之前討論過的無序?qū)懭雴栴}。







          用 volatile 聲明每一個變量怎么樣?

          另一個想法是針對變量 inst 以及 instance 使用關(guān)鍵字 volatile。根據(jù) JLS(參見 參考資料),聲明成 volatile 的變量被認為是順序一致的,即,不是重新排序的。但是試圖使用 volatile 來修正雙重檢查鎖定的問題,會產(chǎn)生以下兩個問題:

          • 這里的問題不是有關(guān)順序一致性的,而是代碼被移動了,不是重新排序。

          • 即使考慮了順序一致性,大多數(shù)的 JVM 也沒有正確地實現(xiàn) volatile

          第二點值得展開討論。假設(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,由于 stopnum 被聲明為 volatile,它們應(yīng)該順序一致。這意味著如果 stop 曾經(jīng)是 truenum 一定曾被設(shè)置成 100。盡管如此,因為許多 JVM 沒有實現(xiàn) volatile 的順序一致性功能,您就不能依賴此行為。因此,如果線程 1 調(diào)用 foo 并且線程 2 并發(fā)地調(diào)用 bar,則線程 1 可能在 num 被設(shè)置成為 100 之前將 stop 設(shè)置成 true。這將導(dǎo)致線程見到 stoptrue,而 num 仍被設(shè)置成 0。使用 volatile 和 64 位變量的原子數(shù)還有另外一些問題,但這已超出了本文的討論范圍。有關(guān)此主題的更多信息,請參閱 參考資料







          解決方案

          底線就是:無論以何種形式,都不應(yīng)使用雙重檢查鎖定,因為您不能保證它在任何 JVM 實現(xiàn)上都能順利運行。JSR-133 是有關(guān)內(nèi)存模型尋址問題的,盡管如此,新的內(nèi)存模型也不會支持雙重檢查鎖定。因此,您有兩種選擇:

          • 接受如清單 2 中所示的 getInstance() 方法的同步。

          • 放棄同步,而使用一個 static 字段。

          選擇項 2 如清單 10 中所示


          清單 10. 使用 static 字段的單例實現(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() 方法時才創(chuàng)建 Singleton。如果您的目標(biāo)是消除同步,則這將是一個很好的選擇。







          String 不是不變的

          鑒于無序?qū)懭牒鸵迷跇?gòu)造函數(shù)執(zhí)行前變成非 null 的問題,您可能會考慮 String 類。假設(shè)有下列代碼:

          private String str;
                      //...
                      str = new String("hello");
                      

          String 類應(yīng)該是不變的。盡管如此,鑒于我們之前討論的無序?qū)懭雴栴},那會在這里導(dǎo)致問題嗎?答案是肯定的。考慮兩個線程訪問 String str。一個線程能看見 str 引用一個 String 對象,在該對象中構(gòu)造函數(shù)尚未運行。事實上,清單 11 包含展示這種情況發(fā)生的代碼。注意,這個代碼僅在我測試用的舊版 JVM 上會失敗。IBM 1.3 和 Sun 1.3 JVM 都會如期生成不變的 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)建一個 MutableString 類,它包含了一個 String 引用,此引用由 //3 處的兩個線程共享。在行 //5 和 //6 處,在兩個分開的線程上創(chuàng)建了兩個對象 StringCreatorStringReader。傳入一個 MutableString 對象的引用。StringCreator 類進入到一個無限循環(huán)中并且使用值“hello”在 //1 處創(chuàng)建 String 對象。StringReader 也進入到一個無限循環(huán)中,并且在 //2 處檢查當(dāng)前的 String 對象的值是不是 “hello”。如果不行,StringReader 線程打印出一條消息并停止。如果 String 類是不變的,則從此程序應(yīng)當(dāng)看不到任何輸出。如果發(fā)生了無序?qū)懭雴栴},則使 StringReader 看到 str 引用的惟一方法絕不是值為“hello”的 String 對象。

          在舊版的 JVM 如 Sun JDK 1.2.1 上運行此代碼會導(dǎo)致無序?qū)懭雴栴}。并因此導(dǎo)致一個非不變的 String







          結(jié)束語

          為避免單例中代價高昂的同步,程序員非常聰明地發(fā)明了雙重檢查鎖定習(xí)語。不幸的是,鑒于當(dāng)前的內(nèi)存模型的原因,該習(xí)語尚未得到廣泛使用,就明顯成為了一種不安全的編程結(jié)構(gòu)。重定義脆弱的內(nèi)存模型這一領(lǐng)域的工作正在進行中。盡管如此,即使是在新提議的內(nèi)存模型中,雙重檢查鎖定也是無效的。對此問題最佳的解決方案是接受同步或者使用一個 static field

          posted @ 2011-05-08 19:17 胡鵬 閱讀(346) | 評論 (0)編輯 收藏

          導(dǎo)航

          <2011年5月>
          24252627282930
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          統(tǒng)計

          • 隨筆 - 93
          • 文章 - 0
          • 評論 - 48
          • 引用 - 0

          常用鏈接

          留言簿(3)

          隨筆分類

          隨筆檔案

          agile

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 临武县| 乌鲁木齐县| 易门县| 历史| 中江县| 奎屯市| 图们市| 曲周县| 苏尼特右旗| 英吉沙县| 乐陵市| 云梦县| 海口市| 平乐县| 岳池县| 芜湖市| 诏安县| 平谷区| 平利县| 广德县| 大城县| 九龙坡区| 灵宝市| 伊宁市| 思南县| 巴彦淖尔市| 中西区| 广宗县| 四会市| 永宁县| 金门县| 青州市| 西畴县| 海淀区| 三门县| 山东省| 保靖县| 安塞县| 萨迦县| 雷山县| 东乡县|