posts - 120,  comments - 19,  trackbacks - 0
            2007年4月9日
          北京英語角(BeiJing)www.52en.com
          =================================
          北大英語角:每周六晚7:00 俄文樓前空地
          清華英語角:每周三晚7:00-10:00 西階(west of Great Hall)
          人大英語角:每周五晚 人大東門花園,老外多,質量不錯
          北外英語角:每周五晚6:30-8:30外研社后花園
          朝陽文化館:每周六下午3:00-5:00 門票6元地點在小莊,收費,但質量好
          posted @ 2007-04-25 09:29 阿成 閱讀(2142) | 評論 (6)編輯 收藏
          1.未到火候,千萬別說。有些男孩才跟人家約過幾次,就提出要建立“更進一步”的關系,這十有八九要壞湯。愛情上的事妙就妙在一切盡在不言中。說清楚了,話挑明了,反而不美。本來人家肯單獨出來跟你說話,這說明女孩對你不無好感。但是這種好感有時連她們自己都說不清,你卻急于挑明,破壞了這種朦朧美,那就別怪人家敬而遠之以致退避三舍了。看看周圍那些還沒開始就夭折的愛情,許多都是由男孩沒有掌握好火候造成的。

            2.收起拳頭是為了更好的出擊。被女孩拒絕了怎么辦呢?有人說應該窮追猛打、堅持不懈。其實不然。除非你是一個啥也不在乎的人,否則你很難承受女孩的白眼和同伴們嘲弄的目光。倒不如偃旗息鼓、暫時撤退。這不僅保護了你的尊嚴而且還留了條后路,從而為日后反攻創造機會。就讓她在人群里闖蕩。等她碰得頭破血流時,你再去找她,她才能認識到原來你才是最愛她的人。即使實在割舍不下,要去找她,也應注意方式方法。千萬別讓她覺得你討厭。而這一點往往是很難做到的。 

            3.不要太露骨。要學會不聲不響地關心她,用你的誠實和善意對待她。只有這樣你才能在一大幫圍著她呱呱亂叫的男孩當中引起她的注意。記住,只有特別的你才會引起她特別的關注。 

            4.非請勿入。一個老是往女孩寢室跑的男孩是不會引起女孩太多的好感的。有些學生會干部借口工作常往女生寢室跑,去了后就老賴在那不走,結果給人家帶來了諸多不便,效果只會適得其反。產生這種結果的根本原因還是因為太露骨。

            5.戰略上藐視...,戰術上重視...。有時你喜愛的女孩會和你有些接觸,比如談談話、聊聊天、一起工作等等。你最好能以平常的心態看待這些事情,不要背上包袱、患得患失。例如不要太在意她無意中說的話,有些男孩容易自作多情,源出于此。但對每一次這樣的機會則應引起足夠的重視,例如初次談話要注意掌握好分寸,最好不要涉及情愛范疇,不妨說說小時候的事。你如果只奔主體那就要糟!女孩非得象警惕狼一樣地警惕你。 

            6.馬屁最好少拍。你夸她長得漂亮,如果她真的漂亮,那么你不過是第七百個夸她漂亮的人,而她映象最深的恐怕是第一個這樣夸她的人;如果她相貌普通,你這樣夸她能產生什么樣的結果誰也說不準。要是讓她發現你言不由衷,那你就死定了。記住,哄女孩只有在女孩成為你的女朋友之后才能哄,還沒追到手就開始哄是沒有掌握好火候的表現。 

            7.少來點大男子主義。有個男孩好不容易請得他傾慕已久的女孩去吃飯,花了他半個月生活費。后來他去付賬時發現女孩已經替他付了,他就要還她錢。女孩不愿意。他覺得女孩剝了他的面子,大為光火。女孩氣得哭了。本來女孩替他付賬這說明她對他有好感,他不思討好反而發脾氣,如此就難怪他要打光棍了。幾乎沒有一個女孩會對那些不尊重女性的男孩有好感,切記!切記!。 

            8.團結大多數。幾乎每個女孩都有一兩個最知心的女友,當其他道路都不通時,她們是你通往勝利的成功之路。你可以通過她們了解女孩到底對你有沒有意思,還可以通過她們傳達你的意思。這比你直接說要好得多。可千萬別忽視這一支生力軍,我不止一次地看到男孩通過這個方法大功告成的。 

            最后要提醒大家的是,愛情從來都沒有固定的公式。別人成功的方法也許正是你的敗著;別人失敗的方法也許恰是你的妙著。我這里只提一點原則性的東西,切不可生搬硬套。如果因此而壞了你的好事切莫來找我。女孩要是不喜歡你,就是玉皇大帝也沒有法子。還是古人說的好:不戰而屈人之兵,上之上策也。
          posted @ 2007-04-23 19:12 阿成 閱讀(515) | 評論 (0)編輯 收藏
          ThreadLocal 類是悄悄地出現在 Java 平臺版本 1.2 中的。雖然支持線程局部變量早就是許多線程工具(例如 Posix pthreads 工具)的一部分,但 Java Threads API 的最初設計卻沒有這項有用的功能。而且,最初的實現也相當低效。由于這些原因, ThreadLocal 極少受到關注,但對簡化線程安全并發程序的開發來說,它卻是很方便的。在 輕松使用線程的第 3 部分,Java 軟件顧問 Brian Goetz 研究了 ThreadLocal 并提供了一些使用技巧。

          參加 Brian 的 多線程 Java 編程討論論壇以獲得您工程中的線程和并發問題的幫助。

          編寫線程安全類是困難的。它不但要求仔細分析在什么條件可以對變量進行讀寫,而且要求仔細分析其它類能如何使用某個類。 有時,要在不影響類的功能、易用性或性能的情況下使類成為線程安全的是很困難的。有些類保留從一個方法調用到下一個方法調用的狀態信息,要在實踐中使這樣的類成為線程安全的是困難的。

          管理非線程安全類的使用比試圖使類成為線程安全的要更容易些。非線程安全類通常可以安全地在多線程程序中使用,只要您能確保一個線程所用的類的實例不被其它線程使用。例如,JDBC Connection 類是非線程安全的 — 兩個線程不能在小粒度級上安全地共享一個 Connection — 但如果每個線程都有它自己的 Connection ,那么多個線程就可以同時安全地進行數據庫操作。

          不使用 ThreadLocal 為每個線程維護一個單獨的 JDBC 連接(或任何其它對象)當然是可能的;Thread API 給了我們把對象和線程聯系起來所需的所有工具。而 ThreadLocal 則使我們能更容易地把線程和它的每線程(per-thread)數據成功地聯系起來。

          什么是線程局部變量(thread-local variable)?

          線程局部變量高效地為每個使用它的線程提供單獨的線程局部變量值的副本。每個線程只能看到與自己相聯系的值,而不知道別的線程可能正在使用或修改它們自己的副本。一些編譯器(例如 Microsoft Visual C++ 編譯器或 IBM XL FORTRAN 編譯器)用存儲類別修飾符(像 staticvolatile )把對線程局部變量的支持集成到了其語言中。Java 編譯器對線程局部變量不提供特別的語言支持;相反地,它用 ThreadLocal 類實現這些支持, 核心 Thread 類中有這個類的特別支持。

          因為線程局部變量是通過一個類來實現的,而不是作為 Java 語言本身的一部分,所以 Java 語言線程局部變量的使用語法比內建線程局部變量語言的使用語法要笨拙一些。要創建一個線程局部變量,請實例化類 ThreadLocal 的一個對象。 ThreadLocal 類的行為與 java.lang.ref 中的各種 Reference 類的行為很相似; ThreadLocal 類充當存儲或檢索一個值時的間接句柄。清單 1 顯示了 ThreadLocal 接口。


          清單 1. ThreadLocal 接口
          
                      public class ThreadLocal {
                      public Object get();
                      public void set(Object newValue);
                      public Object initialValue();
                      }
                      

          get() 訪問器檢索變量的當前線程的值; set() 訪問器修改當前線程的值。 initialValue() 方法是可選的,如果線程未使用過某個變量,那么您可以用這個方法來設置這個變量的初始值;它允許延遲初始化。用一個示例實現來說明 ThreadLocal 的工作方式是最好的方法。清單 2 顯示了 ThreadLocal 的一個實現方式。它不是一個特別好的實現(雖然它與最初實現非常相似),所以很可能性能不佳,但它清楚地說明了 ThreadLocal 的工作方式。


          清單 2. ThreadLocal 的糟糕實現
          
                      public class ThreadLocal {
                      private Map values = Collections.synchronizedMap(new HashMap());
                      public Object get() {
                      Thread curThread = Thread.currentThread();
                      Object o = values.get(curThread);
                      if (o == null && !values.containsKey(curThread)) {
                      o = initialValue();
                      values.put(curThread, o);
                      }
                      return o;
                      }
                      public void set(Object newValue) {
                      values.put(Thread.currentThread(), newValue);
                      }
                      public Object initialValue() {
                      return null;
                      }
                      }
                      

          這個實現的性能不會很好,因為每個 get()set() 操作都需要 values 映射表上的同步,而且如果多個線程同時訪問同一個 ThreadLocal ,那么將發生爭用。此外,這個實現也是不切實際的,因為用 Thread 對象做 values 映射表中的關鍵字將導致無法在線程退出后對 Thread 進行垃圾回收,而且也無法對死線程的 ThreadLocal 的特定于線程的值進行垃圾回收。





          回頁首


          用 ThreadLocal 實現每線程 Singleton

          線程局部變量常被用來描繪有狀態“單子”(Singleton) 或線程安全的共享對象,或者是通過把不安全的整個變量封裝進 ThreadLocal ,或者是通過把對象的特定于線程的狀態封裝進 ThreadLocal 。例如,在與數據庫有緊密聯系的應用程序中,程序的很多方法可能都需要訪問數據庫。在系統的每個方法中都包含一個 Connection 作為參數是不方便的 — 用“單子”來訪問連接可能是一個雖然更粗糙,但卻方便得多的技術。然而,多個線程不能安全地共享一個 JDBC Connection 。如清單 3 所示,通過使用“單子”中的 ThreadLocal ,我們就能讓我們的程序中的任何類容易地獲取每線程 Connection 的一個引用。這樣,我們可以認為 ThreadLocal 允許我們創建 每線程單子


          清單 3. 把一個 JDBC 連接存儲到一個每線程 Singleton 中
          
                      public class ConnectionDispenser {
                      private static class ThreadLocalConnection extends ThreadLocal {
                      public Object initialValue() {
                      return DriverManager.getConnection(ConfigurationSingleton.getDbUrl());
                      }
                      }
                      private ThreadLocalConnection conn = new ThreadLocalConnection();
                      public static Connection getConnection() {
                      return (Connection) conn.get();
                      }
                      }
                      

          任何創建的花費比使用的花費相對昂貴些的有狀態或非線程安全的對象,例如 JDBC Connection 或正則表達式匹配器,都是可以使用每線程單子(singleton)技術的好地方。當然,在類似這樣的地方,您可以使用其它技術,例如用池,來安全地管理共享訪問。然而,從可伸縮性角度看,即使是用池也存在一些潛在缺陷。因為池實現必須使用同步,以維護池數據結構的完整性,如果所有線程使用同一個池,那么在有很多線程頻繁地對池進行訪問的系統中,程序性能將因爭用而降低。





          回頁首


          用 ThreadLocal 簡化調試日志紀錄

          其它適合使用 ThreadLocal 但用池卻不能成為很好的替代技術的應用程序包括存儲或累積每線程上下文信息以備稍后檢索之用這樣的應用程序。例如,假設您想創建一個用于管理多線程應用程序調試信息的工具。您可以用如清單 4 所示的 DebugLogger 類作為線程局部容器來累積調試信息。在一個工作單元的開頭,您清空容器,而當一個錯誤出現時,您查詢該容器以檢索這個工作單元迄今為止生成的所有調試信息。


          清單 4. 用 ThreadLocal 管理每線程調試日志
          
                      public class DebugLogger {
                      private static class ThreadLocalList extends ThreadLocal {
                      public Object initialValue() {
                      return new ArrayList();
                      }
                      public List getList() {
                      return (List) super.get();
                      }
                      }
                      private ThreadLocalList list = new ThreadLocalList();
                      private static String[] stringArray = new String[0];
                      public void clear() {
                      list.getList().clear();
                      }
                      public void put(String text) {
                      list.getList().add(text);
                      }
                      public String[] get() {
                      return list.getList().toArray(stringArray);
                      }
                      }
                      

          在您的代碼中,您可以調用 DebugLogger.put() 來保存您的程序正在做什么的信息,而且,稍后如果有必要(例如發生了一個錯誤),您能夠容易地檢索與某個特定線程相關的調試信息。 與簡單地把所有信息轉儲到一個日志文件,然后努力找出哪個日志記錄來自哪個線程(還要擔心線程爭用日志紀錄對象)相比,這種技術簡便得多,也有效得多。

          ThreadLocal 在基于 servlet 的應用程序或工作單元是一個整體請求的任何多線程應用程序服務器中也是很有用的,因為在處理請求的整個過程中將要用到單個線程。您可以通過前面講述的每線程單子技術用 ThreadLocal 變量來存儲各種每請求(per-request)上下文信息。





          回頁首


          ThreadLocal 的線程安全性稍差的堂兄弟,InheritableThreadLocal

          ThreadLocal 類有一個親戚,InheritableThreadLocal,它以相似的方式工作,但適用于種類完全不同的應用程序。創建一個線程時如果保存了所有 InheritableThreadLocal 對象的值,那么這些值也將自動傳遞給子線程。如果一個子線程調用 InheritableThreadLocalget() ,那么它將與它的父線程看到同一個對象。為保護線程安全性,您應該只對不可變對象(一旦創建,其狀態就永遠不會被改變的對象)使用 InheritableThreadLocal ,因為對象被多個線程共享。 InheritableThreadLocal 很合適用于把數據從父線程傳到子線程,例如用戶標識(user id)或事務標識(transaction id),但不能是有狀態對象,例如 JDBC Connection





          回頁首


          ThreadLocal 的性能

          雖然線程局部變量早已赫赫有名并被包括 Posix pthreads 規范在內的很多線程框架支持,但最初的 Java 線程設計中卻省略了它,只是在 Java 平臺的版本 1.2 中才添加上去。在很多方面, ThreadLocal 仍在發展之中;在版本 1.3 中它被重寫,版本 1.4 中又重寫了一次,兩次都專門是為了性能問題。

          在 JDK 1.2 中, ThreadLocal 的實現方式與清單 2 中的方式非常相似,除了用同步 WeakHashMap 代替 HashMap 來存儲 values 之外。(以一些額外的性能開銷為代價,使用 WeakHashMap 解決了無法對 Thread 對象進行垃圾回收的問題。)不用說, ThreadLocal 的性能是相當差的。

          Java 平臺版本 1.3 提供的 ThreadLocal 版本已經盡量更好了;它不使用任何同步,從而不存在可伸縮性問題,而且它也不使用弱引用。相反地,人們通過給 Thread 添加一個實例變量(該變量用于保存當前線程的從線程局部變量到它的值的映射的 HashMap )來修改 Thread 類以支持 ThreadLocal 。因為檢索或設置一個線程局部變量的過程不涉及對可能被另一個線程讀寫的數據的讀寫操作,所以您可以不用任何同步就實現 ThreadLocal.get()set() 。而且,因為每線程值的引用被存儲在自已的 Thread 對象中,所以當對 Thread 進行垃圾回收時,也能對該 Thread 的每線程值進行垃圾回收。

          不幸的是,即使有了這些改進,Java 1.3 中的 ThreadLocal 的性能仍然出奇地慢。據我的粗略測量,在雙處理器 Linux 系統上的 Sun 1.3 JDK 中進行 ThreadLocal.get() 操作,所耗費的時間大約是無爭用同步的兩倍。性能這么差的原因是 Thread.currentThread() 方法的花費非常大,占了 ThreadLocal.get() 運行時間的三分之二還多。雖然有這些缺點,JDK 1.3 ThreadLocal.get() 仍然比爭用同步快得多,所以如果在任何存在嚴重爭用的地方(可能是有非常多的線程,或者同步塊被頻繁地執行,或者同步塊很大), ThreadLocal 可能仍然要高效得多。

          在 Java 平臺的最新版本,即版本 1.4b2 中, ThreadLocalThread.currentThread() 的性能都有了很大提高。有了這些提高, ThreadLocal 應該比其它技術,如用池,更快。由于它比其它技術更簡單,也更不易出錯,人們最終將發現它是避免線程間出現不希望的交互的有效途徑。





          回頁首


          ThreadLocal 的好處

          ThreadLocal 能帶來很多好處。它常常是把有狀態類描繪成線程安全的,或者封裝非線程安全類以使它們能夠在多線程環境中安全地使用的最容易的方式。使用 ThreadLocal 使我們可以繞過為實現線程安全而對何時需要同步進行判斷的復雜過程,而且因為它不需要任何同步,所以也改善了可伸縮性。除簡單之外,用 ThreadLocal 存儲每線程單子或每線程上下文信息在歸檔方面還有一個頗有價值好處 — 通過使用 ThreadLocal ,存儲在 ThreadLocal 中的對象都是 被線程共享的是清晰的,從而簡化了判斷一個類是否線程安全的工作。

          我希望您從這個系列中得到了樂趣,也學到了知識,我也鼓勵您到我的 討論論壇中來深入研究多線程問題。

          posted @ 2007-04-09 20:52 阿成 閱讀(2440) | 評論 (1)編輯 收藏

          Servlet是在多線程環境下的。即可能有多個請求發給一個servelt實例,每個請求是一個線程。
          struts下的action也類似,同樣在多線程環境下。可以參考struts user guide: http://struts.apache.org/struts-action/userGuide/building_controller.html 中的Action Class Design Guidelines一節: Write code for a multi-threaded environment - Our controller servlet creates only one instance of your Action class, and uses this one instance to service all requests. Thus, you need to write thread-safe Action classes. Follow the same guidelines you would use to write thread-safe Servlets.
          譯:為多線程環境編寫代碼。我們的controller servlet指揮創建你的Action 類的一個實例,用此實例來服務所有的請求。因此,你必須編寫線程安全的Action類。遵循與寫線程安全的servlet同樣的方針。

          1.什么是線程安全的代碼
          在多線程環境下能正確執行的代碼就是線程安全的。
          安全的意思是能正確執行,否則后果是程序執行錯誤,可能出現各種異常情況。

          2.如何編寫線程安全的代碼
          很多書籍里都詳細講解了如何這方面的問題,他們主要講解的是如何同步線程對共享資源的使用的問題。主要是對synchronized關鍵字的各種用法,以及鎖的概念。
          Java1.5中也提供了如讀寫鎖這類的工具類。這些都需要較高的技巧,而且相對難于調試。

          但是,線程同步是不得以的方法,是比較復雜的,而且會帶來性能的損失。等效的代碼中,不需要同步在編寫容易度和性能上會更好些。
          我這里強調的是什么代碼是始終為線程安全的、是不需要同步的。如下:
          1)常量始終是線程安全的,因為只存在讀操作。
          2)對構造器的訪問(new 操作)是線程安全的,因為每次都新建一個實例,不會訪問共享的資源。
          3)最重要的是:局部變量是線程安全的。因為每執行一個方法,都會在獨立的空間創建局部變量,它不是共享的資源。局部變量包括方法的參數變量。
          struts user guide里有:
          Only Use Local Variables - The most important principle that aids in thread-safe coding is to use only local variables, not instance variables , in your Action class.
          譯:只使用用局部變量。--編寫線程安全的代碼最重要的原則就是,在Action類中只使用局部變量,不使用實例變量。


          總結:
          在Java的Web服務器環境下開發,要注意線程安全的問題。最簡單的實現方式就是在Servlet和Struts Action里不要使用類變量、實例變量,但可以使用類常量和實例常量。
          如果有這些變量,可以將它們轉換為方法的參數傳入,以消除它們。
          注意一個容易混淆的地方:被Servlet或Action調用的類中(如值對象、領域模型類)中是否可以安全的使用實例變量?如果你在每次方法調用時
          新建一個對象,再調用它們的方法,則不存在同步問題---因為它們不是多個線程共享的資源,只有共享的資源才需要同步---而Servlet和Action的實例對于多個線程是共享的。
          換句話說,Servlet和Action的實例會被多個線程同時調用,而過了這一層,如果在你自己的代碼中沒有另外啟動線程,且每次調用后續業務對象時都是先新建一個實例再調用,則都是線程安全的。

          posted @ 2007-04-09 20:31 阿成 閱讀(498) | 評論 (0)編輯 收藏
          主站蜘蛛池模板: 芦山县| 兴城市| 永吉县| 新巴尔虎左旗| 璧山县| 阿拉善右旗| 陇南市| 博乐市| 哈巴河县| 二连浩特市| 罗江县| 涟源市| 灵璧县| 余姚市| 左权县| 宝鸡市| 泸西县| 泰宁县| 徐汇区| 措勤县| 锦屏县| 桦甸市| 新野县| 贵阳市| 东城区| 镇江市| 阳春市| 班玛县| 阜城县| 鄂托克前旗| 南投市| 吐鲁番市| 大安市| 沈丘县| 雷州市| 合肥市| 乌拉特前旗| 扎赉特旗| 同仁县| 通山县| 上犹县|