posts - 110, comments - 101, trackbacks - 0, articles - 7
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

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

          搜索了一下,應該是非正常關機導致eclipse工作區的文件狀態錯誤導致。在工作區目錄中,有一個.metadata目錄,里面是工作區及各插件的信息,刪除此目錄可以解決問題。

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

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

          怎么辦?這時想到啟動停止時顯示的狀態:"Loading workbench",看來和這個workbench插件有關。查看原來的.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

          發現了兩個: org.eclipse.ui.workbenchorg.eclipse.ui.workbench.texteditor

          不管三七二十一,刪了這兩個目錄,重新啟動eclipse。正常啟動且原項目信息正確加載。

          posted @ 2013-04-01 09:57 云云 閱讀(662) | 評論 (0)編輯 收藏

           原文:http://www.iteye.com/topic/1118660

          整個ThreadPoolExecutor的任務處理有4步操作:

           

          • 第一步,初始的poolSize < corePoolSize,提交的runnable任務,會直接做為new一個Thread的參數,立馬執行
          • 第二步,當提交的任務數超過了corePoolSize,就進入了第二步操作。會將當前的runable提交到一個block queue中
          • 第三步,如果block queue是個有界隊列,當隊列滿了之后就進入了第三步。如果poolSize < maximumPoolsize時,會嘗試new 一個Thread的進行救急處理,立馬執行對應的runnable任務
          • 第四步,如果第三步救急方案也無法處理了,就會走到第四步執行reject操作。
          幾點說明:(相信這些網上一搜一大把,我這里簡單介紹下,為后面做一下鋪墊)
          • block queue有以下幾種實現:
            1. ArrayBlockingQueue :  有界的數組隊列
            2. LinkedBlockingQueue : 可支持有界/無界的隊列,使用鏈表實現
            3. PriorityBlockingQueue : 優先隊列,可以針對任務排序
            4. SynchronousQueue : 隊列長度為1的隊列,和Array有點區別就是:client thread提交到block queue會是一個阻塞過程,直到有一個worker thread連接上來poll task。
          • RejectExecutionHandler是針對任務無法處理時的一些自保護處理:
            1. Reject 直接拋出Reject exception
            2. Discard 直接忽略該runnable,不可取
            3. DiscardOldest 丟棄最早入隊列的的任務
            4. CallsRun 直接讓原先的client thread做為worker線程,進行執行

          容易被人忽略的點:
          1.  pool threads啟動后,以后的任務獲取都會通過block queue中,獲取堆積的runnable task.

          所以建議: block size >= corePoolSize ,不然線程池就沒任何意義
          2.  corePoolSize 和 maximumPoolSize的區別, 和大家正常理解的數據庫連接池不太一樣。
            *  據dbcp pool為例,會有minIdle , maxActive配置。minIdle代表是常駐內存中的threads數量,maxActive代表是工作的最大線程數。
            *  這里的corePoolSize就是連接池的maxActive的概念,它沒有minIdle的概念(每個線程可以設置keepAliveTime,超過多少時間多有任務后銷毀線程,但不會固定保持一定數量的threads)。 
            * 這里的maximumPoolSize,是一種救急措施的第一層。當threadPoolExecutor的工作threads存在滿負荷,并且block queue隊列也滿了,這時代表接近崩潰邊緣。這時允許臨時起一批threads,用來處理runnable,處理完后立馬退出。

          所以建議:  maximumPoolSize >= corePoolSize =期望的最大線程數。 (我曾經配置了corePoolSize=1, maximumPoolSize=20, blockqueue為無界隊列,最后就成了單線程工作的pool。典型的配置錯誤)

          3. 善用blockqueue和reject組合. 這里要重點推薦下CallsRun的Rejected Handler,從字面意思就是讓調用者自己來運行。
          我們經常會在線上使用一些線程池做異步處理,比如我前面做的(業務層)異步并行加載技術分析和設計將原本串行的請求都變為了并行操作,但過多的并行會增加系統的負載(比如軟中斷,上下文切換)。所以肯定需要對線程池做一個size限制。但是為了引入異步操作后,避免因在block queue的等待時間過長,所以需要在隊列滿的時,執行一個callsRun的策略,并行的操作又轉為一個串行處理,這樣就可以保證盡量少的延遲影響。

          所以建議:  RejectExecutionHandler = CallsRun ,  blockqueue size = 2 * poolSize (為啥是2倍poolSize,主要一個考慮就是瞬間高峰處理,允許一個thread等待一個runnable任務)

          Btrace容量規劃

          再提供一個btrace腳本,分析線上的thread pool容量規劃是否合理,可以運行時輸出poolSize等一些數據。

           

           

          Java代碼  
          1. import static com.sun.btrace.BTraceUtils.addToAggregation;   
          2. import static com.sun.btrace.BTraceUtils.field;   
          3. import static com.sun.btrace.BTraceUtils.get;   
          4. import static com.sun.btrace.BTraceUtils.newAggregation;   
          5. import static com.sun.btrace.BTraceUtils.newAggregationKey;   
          6. import static com.sun.btrace.BTraceUtils.printAggregation;   
          7. import static com.sun.btrace.BTraceUtils.println;   
          8. import static com.sun.btrace.BTraceUtils.str;   
          9. import static com.sun.btrace.BTraceUtils.strcat;   
          10.   
          11. import java.lang.reflect.Field;   
          12. import java.util.concurrent.atomic.AtomicInteger;   
          13.   
          14. import com.sun.btrace.BTraceUtils;   
          15. import com.sun.btrace.aggregation.Aggregation;   
          16. import com.sun.btrace.aggregation.AggregationFunction;   
          17. import com.sun.btrace.aggregation.AggregationKey;   
          18. import com.sun.btrace.annotations.BTrace;   
          19. import com.sun.btrace.annotations.Kind;   
          20. import com.sun.btrace.annotations.Location;   
          21. import com.sun.btrace.annotations.OnEvent;   
          22. import com.sun.btrace.annotations.OnMethod;   
          23. import com.sun.btrace.annotations.OnTimer;   
          24. import com.sun.btrace.annotations.Self;   
          25.   
          26. /**  
          27.  * 并行加載監控  
          28.  *   
          29.  * @author jianghang 2011-4-7 下午10:59:53  
          30.  */  
          31. @BTrace  
          32. public class AsyncLoadTracer {   
          33.   
          34.     private static AtomicInteger rejecctCount = BTraceUtils.newAtomicInteger(0);   
          35.     private static Aggregation   histogram    = newAggregation(AggregationFunction.QUANTIZE);   
          36.     private static Aggregation   average      = newAggregation(AggregationFunction.AVERAGE);   
          37.     private static Aggregation   max          = newAggregation(AggregationFunction.MAXIMUM);   
          38.     private static Aggregation   min          = newAggregation(AggregationFunction.MINIMUM);   
          39.     private static Aggregation   sum          = newAggregation(AggregationFunction.SUM);   
          40.     private static Aggregation   count        = newAggregation(AggregationFunction.COUNT);   
          41.   
          42.     @OnMethod(clazz = "java.util.concurrent.ThreadPoolExecutor", method = "execute", location = @Location(value = Kind.ENTRY))   
          43.     public static void executeMonitor(@Self Object self) {   
          44.         Field poolSizeField = field("java.util.concurrent.ThreadPoolExecutor""poolSize");   
          45.         Field largestPoolSizeField = field("java.util.concurrent.ThreadPoolExecutor""largestPoolSize");   
          46.         Field workQueueField = field("java.util.concurrent.ThreadPoolExecutor""workQueue");   
          47.   
          48.         Field countField = field("java.util.concurrent.ArrayBlockingQueue""count");   
          49.         int poolSize = (Integer) get(poolSizeField, self);   
          50.         int largestPoolSize = (Integer) get(largestPoolSizeField, self);   
          51.         int queueSize = (Integer) get(countField, get(workQueueField, self));   
          52.   
          53.         println(strcat(strcat(strcat(strcat(strcat("poolSize : ", str(poolSize)), " largestPoolSize : "),   
          54.                                      str(largestPoolSize)), " queueSize : "), str(queueSize)));   
          55.     }   
          56.   
          57.     @OnMethod(clazz = "java.util.concurrent.ThreadPoolExecutor", method = "reject", location = @Location(value = Kind.ENTRY))   
          58.     public static void rejectMonitor(@Self Object self) {   
          59.         String name = str(self);   
          60.         if (BTraceUtils.startsWith(name, "com.alibaba.pivot.common.asyncload.impl.pool.AsyncLoadThreadPool")) {   
          61.             BTraceUtils.incrementAndGet(rejecctCount);   
          62.         }   
          63.     }   
          64.   
          65.     @OnTimer(1000)   
          66.     public static void rejectPrintln() {   
          67.         int reject = BTraceUtils.getAndSet(rejecctCount, 0);   
          68.         println(strcat("reject count in 1000 msec: ", str(reject)));   
          69.         AggregationKey key = newAggregationKey("rejectCount");   
          70.         addToAggregation(histogram, key, reject);   
          71.         addToAggregation(average, key, reject);   
          72.         addToAggregation(max, key, reject);   
          73.         addToAggregation(min, key, reject);   
          74.         addToAggregation(sum, key, reject);   
          75.         addToAggregation(count, key, reject);   
          76.     }   
          77.   
          78.     @OnEvent  
          79.     public static void onEvent() {   
          80.         BTraceUtils.truncateAggregation(histogram, 10);   
          81.         println("---------------------------------------------");   
          82.         printAggregation("Count", count);   
          83.         printAggregation("Min", min);   
          84.         printAggregation("Max", max);   
          85.         printAggregation("Average", average);   
          86.         printAggregation("Sum", sum);   
          87.         printAggregation("Histogram", histogram);   
          88.         println("---------------------------------------------");   
          89.     }   
          90. }  
           

          運行結果:

           

          Java代碼  
          1. poolSize : 1 , largestPoolSize = 10 , queueSize = 10  
          2. reject count in 1000 msec: 0  

           

          說明:

          1. poolSize 代表為當前的線程數

          2. largestPoolSize 代表為歷史最大的線程數

          3. queueSize 代表blockqueue的當前堆積的size

          4. reject count 代表在1000ms內的被reject的數量

           

           

          最后

            這是我對ThreadPoolExecutor使用過程中的一些經驗總結,希望能對大家有所幫助,如有描述不對的地方歡迎拍磚。

          posted @ 2013-01-14 16:08 云云 閱讀(392) | 評論 (0)編輯 收藏

          1. 堆大小設置
            JVM 中最大堆大小有三方面限制:相關操作系統的數據模型(32-bt還是64-bit)限制;系統的可用虛擬內存限制;系統的可用物理內存限制。32位系統下,一般限制在1.5G~2G;64為操作系統對內存無限制。我在Windows Server 2003 系統,3.5G物理內存,JDK5.0下測試,最大可設置為1478m。
            典型設置:
            • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
              -
              Xmx3550m:設置JVM最大可用內存為3550M。
              -Xms3550m
              :設置JVM促使內存為3550m。此值可以設置與-Xmx相同,以避免每次垃圾回收完成后JVM重新分配內存。
              -Xmn2g
              :設置年輕代大小為2G。整個JVM內存大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代后,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8。
              -Xss128k
              :設置每個線程的堆棧大小。JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。更具應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,經驗值在3000~5000左右。
            • java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
              -XX:NewRatio=4
              :設置年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設置為4,則年輕代與年老代所占比值為1:4,年輕代占整個堆棧的1/5
              -XX:SurvivorRatio=4
              :設置年輕代中Eden區與Survivor區的大小比值。設置為4,則兩個Survivor區與一個Eden區的比值為2:4,一個Survivor區占整個年輕代的1/6
              -XX:MaxPermSize=16m:設置持久代大小為16m。
              -XX:MaxTenuringThreshold=0:設置垃圾最大年齡。如果設置為0的話,則年輕代對象不經過Survivor區,直接進入年老代。對于年老代比較多的應用,可以提高效率。如果將此值設置為一個較大值,則年輕代對象會在Survivor區進行多次復制,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概論。
          2. 回收器選擇
            JVM給了三種選擇:串行收集器、并行收集器、并發收集器,但是串行收集器只適用于小數據量的情況,所以這里的選擇主要針對并行收集器和并發收集器。默認情況下,JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在啟動時加入相應參數。JDK5.0以后,JVM會根據當前系統配置進行判斷。
            1. 吞吐量優先的并行收集器
              如上文所述,并行收集器主要以到達一定的吞吐量為目標,適用于科學技術和后臺處理等。
              典型配置
              • java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
                -XX:+UseParallelGC
                :選擇垃圾收集器為并行收集器。此配置僅對年輕代有效。即上述配置下,年輕代使用并發收集,而年老代仍舊使用串行收集。
                -XX:ParallelGCThreads=20:配置并行收集器的線程數,即:同時多少個線程一起進行垃圾回收。此值最好配置與處理器數目相等。
              • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
                -XX:+UseParallelOldGC:配置年老代垃圾收集方式為并行收集。JDK6.0支持對年老代并行收集。
              • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC  -XX:MaxGCPauseMillis=100
                -XX:MaxGCPauseMillis=100:設置每次年輕代垃圾回收的最長時間,如果無法滿足此時間,JVM會自動調整年輕代大小,以滿足此值。
              • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC  -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy
                -XX:+UseAdaptiveSizePolicy
                :設置此選項后,并行收集器會自動選擇年輕代區大小和相應的Survivor區比例,以達到目標系統規定的最低相應時間或者收集頻率等,此值建議使用并行收集器時,一直打開。
            2. 響應時間優先的并發收集器
              如上文所述,并發收集器主要是保證系統的響應時間,減少垃圾收集時的停頓時間。適用于應用服務器、電信領域等。
              典型配置
              • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
                -XX:+UseConcMarkSweepGC:設置年老代為并發收集。測試中配置這個以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此時年輕代大小最好用-Xmn設置。
                -XX:+UseParNewGC:設置年輕代為并行收集。可與CMS收集同時使用。JDK5.0以上,JVM會根據系統配置自行設置,所以無需再設置此值。
              • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
                -XX:CMSFullGCsBeforeCompaction:由于并發收集器不對內存空間進行壓縮、整理,所以運行一段時間以后會產生“碎片”,使得運行效率降低。此值設置運行多少次GC以后對內存空間進行壓縮、整理。
                -XX:+UseCMSCompactAtFullCollection:打開對年老代的壓縮。可能會影響性能,但是可以消除碎片
          3. 輔助信息
            JVM提供了大量命令行參數,打印信息,供調試使用。主要有以下一些:
            • -XX:+PrintGC
              輸出形式:[GC 118250K->113543K(130112K), 0.0094143 secs]

                              [Full GC 121376K->10414K(130112K), 0.0650971 secs]

            • -XX:+PrintGCDetails
              輸出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]

                              [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

            • -XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可與上面兩個混合使用
              輸出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
            • -XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,程序未中斷的執行時間。可與上面混合使用
              輸出形式:Application time: 0.5291524 seconds
            • -XX:+PrintGCApplicationStoppedTime:打印垃圾回收期間程序暫停的時間。可與上面混合使用
              輸出形式:Total time for which application threads were stopped: 0.0468229 seconds
            • -XX:PrintHeapAtGC:打印GC前后的詳細堆棧信息
              輸出形式:
              34.702: [GC {Heap before gc invocations=7:
               def new generation   total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)
              eden space 49152K,  99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)
              from space 6144K,  55% used [0x221d0000, 0x22527e10, 0x227d0000)
                to   space 6144K,   0% used [0x21bd0000, 0x21bd0000, 0x221d0000)
               tenured generation   total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)
              the space 69632K,   3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)
               compacting perm gen  total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
                 the space 8192K,  35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
                  ro space 8192K,  66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
                  rw space 12288K,  46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
              34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:
               def new generation   total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)
              eden space 49152K,   0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)
                from space 6144K,  55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)
                to   space 6144K,   0% used [0x221d0000, 0x221d0000, 0x227d0000)
               tenured generation   total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)
              the space 69632K,   4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)
               compacting perm gen  total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
                 the space 8192K,  35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
                  ro space 8192K,  66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
                  rw space 12288K,  46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
              }
              , 0.0757599 secs]
            • -Xloggc:filename:與上面幾個配合使用,把相關日志信息記錄到文件以便分析。
          4. 常見配置匯總
            1. 堆設置
              • -Xms:初始堆大小
              • -Xmx:最大堆大小
              • -XX:NewSize=n:設置年輕代大小
              • -XX:NewRatio=n:設置年輕代和年老代的比值。如:為3,表示年輕代與年老代比值為1:3,年輕代占整個年輕代年老代和的1/4
              • -XX:SurvivorRatio=n:年輕代中Eden區與兩個Survivor區的比值。注意Survivor區有兩個。如:3,表示Eden:Survivor=3:2,一個Survivor區占整個年輕代的1/5
              • -XX:MaxPermSize=n:設置持久代大小
            2. 收集器設置
              • -XX:+UseSerialGC:設置串行收集器
              • -XX:+UseParallelGC:設置并行收集器
              • -XX:+UseParalledlOldGC:設置并行年老代收集器
              • -XX:+UseConcMarkSweepGC:設置并發收集器
            3. 垃圾回收統計信息
              • -XX:+PrintGC
              • -XX:+PrintGCDetails
              • -XX:+PrintGCTimeStamps
              • -Xloggc:filename
            4. 并行收集器設置
              • -XX:ParallelGCThreads=n:設置并行收集器收集時使用的CPU數。并行收集線程數。
              • -XX:MaxGCPauseMillis=n:設置并行收集最大暫停時間
              • -XX:GCTimeRatio=n:設置垃圾回收時間占程序運行時間的百分比。公式為1/(1+n)
            5. 并發收集器設置
              • -XX:+CMSIncrementalMode:設置為增量模式。適用于單CPU情況。
              • -XX:ParallelGCThreads=n:設置并發收集器年輕代收集方式為并行收集時,使用的CPU數。并行收集線程數。


          四、調優總結

          1. 年輕代大小選擇
            • 響應時間優先的應用盡可能設大,直到接近系統的最低響應時間限制(根據實際情況選擇)。在此種情況下,年輕代收集發生的頻率也是最小的。同時,減少到達年老代的對象。
            • 吞吐量優先的應用:盡可能的設置大,可能到達Gbit的程度。因為對響應時間沒有要求,垃圾收集可以并行進行,一般適合8CPU以上的應用。
          2. 年老代大小選擇
            • 響應時間優先的應用:年老代使用并發收集器,所以其大小需要小心設置,一般要考慮并發會話率會話持續時間等一些參數。如果堆設置小了,可以會造成內存碎片、高回收頻率以及應用暫停而使用傳統的標記清除方式;如果堆大了,則需要較長的收集時間。最優化的方案,一般需要參考以下數據獲得:
              • 并發垃圾收集信息
              • 持久代并發收集次數
              • 傳統GC信息
              • 花在年輕代和年老代回收上的時間比例
              減少年輕代和年老代花費的時間,一般會提高應用的效率
            • 吞吐量優先的應用:一般吞吐量優先的應用都有一個很大的年輕代和一個較小的年老代。原因是,這樣可以盡可能回收掉大部分短期對象,減少中期的對象,而年老代盡存放長期存活對象。
          3. 較小堆引起的碎片問題
            因為年老代的并發收集器使用標記、清除算法,所以不會對堆進行壓縮。當收集器回收時,他會把相鄰的空間進行合并,這樣可以分配給較大的對象。但是,當堆空間較小時,運行一段時間以后,就會出現“碎片”,如果并發收集器找不到足夠的空間,那么并發收集器將會停止,然后使用傳統的標記、清除方式進行回收。如果出現“碎片”,可能需要進行如下配置:
            • -XX:+UseCMSCompactAtFullCollection:使用并發收集器時,開啟對年老代的壓縮。
            • -XX:CMSFullGCsBeforeCompaction=0:上面配置開啟的情況下,這里設置多少次Full GC后,對年老代進行壓縮

          posted @ 2013-01-11 14:18 云云 閱讀(1208) | 評論 (0)編輯 收藏

          google的guava工具包的確很多好東西,包括之前的字符串處理工具類的,還有大量的collection相關的,項目地址在:http://code.google.com/p/guava-libraries/
          留意到其中的collection相關類中的map,簡單介紹如下,更多的請大家補充挖掘或者
          看原來的文檔:



              guava提供的是多值map!,就是說,一個key,可以對應多個value了,比如一個人會有多個聯系號碼等,可以表達為:
              multimap<String,String> phonebook=ArrayListMultmap.create();
              phonebook.put("a","43434");
              phonebook.put("b","3434434");
            system.out.println(phonebook,get("a"));


            還有map的查詢:
            
          Java代碼
          1. Map<String, Integer> user = new HashMap<String, Integer>();   
          2.         user.put("張三"20);   
          3.         user.put("李四"22);   
          4.         user.put("王五"25);   
          5.         // 所有年齡大于20歲的人員   
          6.         Map<String, Integer> filtedMap = Maps.filterValues(user,   
          7.                 new Predicate<Integer>() {   
          8.                     public boolean apply(Integer value) {   
          9.                         return value > 20;   
          10.                     }   
          11.                 });   
          12.         System.out.println(filtedMap);  


             再來點例子,加深了解:

            
          Java代碼
          1.   
          2. public class MutliMapTest {   
          3.     public static void main(String... args) {   
          4.   Multimap<String, String> myMultimap = ArrayListMultimap.create();   
          5.   
          6.   // Adding some key/value   
          7.   myMultimap.put('Fruits''Bannana');   
          8.   myMultimap.put('Fruits''Apple');   
          9.   myMultimap.put('Fruits''Pear');   
          10.   myMultimap.put('Vegetables''Carrot');   
          11.   
          12.   // Getting the size   
          13.   int size = myMultimap.size();   
          14.   System.out.println(size);  // 4   
          15.   
          16.     
          17.   Collection<string> fruits = myMultimap.get('Fruits');   
          18.   System.out.println(fruits); // [Bannana, Apple, Pear]   
          19.   
          20.   Collection<string> vegetables = myMultimap.get('Vegetables');   
          21.   System.out.println(vegetables); // [Carrot]   
          22.   
          23.   // 循環輸出   
          24.   for(String value : myMultimap.values()) {   
          25.    System.out.println(value);   
          26.   }   
          27.   
          28.   // 移走某個值   
          29.   myMultimap.remove('Fruits','Pear');   
          30.   System.out.println(myMultimap.get('Fruits')); // [Bannana, Pear]   
          31.   
          32.   //移走某個KEY的所有對應value   
          33.   myMultimap.removeAll('Fruits');   
          34.   System.out.println(myMultimap.get('Fruits')); // [] (Empty Collection!)   
          35.  }   
          36. }  


            更詳細的看:
          http://docs.guava-libraries.googlecode.com/git-history/release09/javadoc/com/google/common/collect/Multimap.html

          posted @ 2012-12-13 22:00 云云 閱讀(2141) | 評論 (0)編輯 收藏

          最近老是出現雙擊啟動后,確定完workspace后,顯示啟動畫面,沒過一會就進入灰色無響應狀態。啟動畫面始終停留在Loading workbench狀態。反復重啟,狀態依舊。
          在網上看到有人已經解決了,嘗試使用后的確可以解決問題,所以留下分享。

          搜索了一下,應該是非正常關機導致eclipse工作區的文件狀態錯誤導致。在工作區目錄中,有一個.metadata目錄,里面是工作區及各插件的信息,刪除此目錄可以解決問題。

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

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

          咋辦?這時想到啟動停止時顯示的狀態:"Loading workbench",看來和這個workbench插件有關。查看原來的.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

          發現了兩個:org.eclipse.ui.workbench和 org.eclipse.ui.workbench.texteditor。

          不管三七二十一,刪了這兩個目錄,重新啟動eclipse。正常啟動且原項目信息正確加載。

          posted @ 2012-12-05 10:03 云云 閱讀(742) | 評論 (0)編輯 收藏

          1.synchronized與static synchronized 的區別

                  synchronized是對類的當前實例進行加鎖,防止其他線程同時訪問該類的該實例的所有synchronized塊,注意這里是“類的當前實例”, 類的兩個不同實例就沒有這種約束了。那么static synchronized恰好就是要控制類的所有實例的訪問了,static synchronized是限制線程同時訪問jvm中該類的所有實例同時訪問對應的代碼快。實際上,在類中某方法或某代碼塊中有 synchronized,那么在生成一個該類實例后,改類也就有一個監視快,放置線程并發訪問改實例synchronized保護快,而static synchronized則是所有該類的實例公用一個監視快了,也也就是兩個的區別了,也就是synchronized相當于 this.synchronized,而static synchronized相當于Something.synchronized.
                   一個日本作者-結成浩的《java多線程設計模式》有這樣的一個列子:

          pulbic class Something(){ 
              publicsynchronizedvoid isSyncA(){} 
              publicsynchronizedvoid isSyncB(){} 
              publicstaticsynchronizedvoid cSyncA(){} 
              publicstaticsynchronizedvoid cSyncB(){} 
          } 
                 那么,加入有Something類的兩個實例a與b,那么下列組方法何以被1個以上線程同時訪問呢

          a. x.isSyncA()與x.isSyncB()  
          b. x.isSyncA()與y.isSyncA() 
          c. x.cSyncA()與y.cSyncB() 
          d. x.isSyncA()與Something.cSyncA() 
                這里,很清楚的可以判斷:

          a,都是對同一個實例的synchronized域訪問,因此不能被同時訪問 b,是針對不同實例的,因此可以同時被訪問 c,因為是static synchronized,所以不同實例之間仍然會被限制,相當于Something.isSyncA()與 Something.isSyncB()了,因此不能被同時訪問。 那么,第d呢?,書上的 答案是可以被同時訪問的,答案理由是synchronzied的是實例方法與synchronzied的類方法由于鎖定(lock)不同的原因。 個人分析也就是synchronized 與static synchronized 相當于兩幫派,各自管各自,相互之間就無約束了,可以被同時訪問。目前還不是分清楚java內部設計synchronzied是怎么樣實現的。
          結論:A: synchronized static是某個類的范圍,synchronized static cSync{}防止多個線程同時訪問這個 類中的synchronized static 方法。它可以對類的所有對象實例起作用。
          B: synchronized 是某實例的范圍,synchronized isSync(){}防止多個線程同時訪問這個實例中的synchronized 方法。


          2.synchronized方法與synchronized代碼快的區別 

                  synchronized methods(){} 與synchronized(this){}之間沒有什么區別,只是synchronized methods(){} 便于閱讀理解,而synchronized(this){}可以更精確的控制沖突限制訪問區域,有時候表現更高效率。


          3.synchronized關鍵字是不能繼承的

                   這個在《搞懂java中的synchronized關鍵字》一文中看到的,我想這一點也是很值得注意的,繼承時子類的覆蓋方法必須顯示定義成synchronized。(但是如果使用繼承開發環境的話,會默認加上synchronized關鍵字)

          posted @ 2012-12-01 21:27 云云 閱讀(2625) | 評論 (0)編輯 收藏

          在Java中,為了保證多線程讀寫數據時保證數據的一致性,可以采用兩種方式:

          同步

          如用synchronized關鍵字,或者使用鎖對象.

          volatile

          使用volatile關鍵字
          用一句話概括volatile,它能夠使變量在值發生改變時能盡快地讓其他線程知道.

          volatile詳解

          首先我們要先意識到有這樣的現象,編譯器為了加快程序運行的速度,對一些變量的寫操作會先在寄存器或者是CPU緩存上進行,最后才寫入內存.
          而在這個過程,變量的新值對其他線程是不可見的.而volatile的作用就是使它修飾的變量的讀寫操作都必須在內存中進行!

          volatile與synchronized

            volatile本質是在告訴jvm當前變量在寄存器中的值是不確定的,需要從主存中讀取,synchronized則是鎖定當前變量,只有當前線程可以訪問該變量,其他線程被阻塞住.
            volatile僅能使用在變量級別,synchronized則可以使用在變量,方法.
            volatile僅能實現變量的修改可見性,但不具備原子特性,而synchronized則可以保證變量的修改可見性和原子性.
            volatile不會造成線程的阻塞,而synchronized可能會造成線程的阻塞.
            volatile標記的變量不會被編譯器優化,而synchronized標記的變量可以被編譯器優化.

          posted @ 2012-12-01 21:19 云云 閱讀(13708) | 評論 (0)編輯 收藏

          一般大家都知道ArrayList和LinkedList的大致區別:
               1.ArrayList是實現了基于動態數組的數據結構,LinkedList基于鏈表的數據結構。
               2.對于隨機訪問get和set,ArrayList覺得優于LinkedList,因為LinkedList要移動指針。
               3.對于新增和刪除操作add和remove,LinedList比較占優勢,因為ArrayList要移動數據。

          ArrayList和LinkedList是兩個集合類,用于存儲一系列的對象引用(references)。例如我們可以用ArrayList來存儲一系列的String或者Integer。那么ArrayList和LinkedList在性能上有什么差別呢?什么時候應該用ArrayList什么時候又該用LinkedList呢?


          一.時間復雜度
          首先一點關鍵的是,ArrayList的內部實現是基于基礎的對象數組的,因此,它使用get方法訪問列表中的任意一個元素時(random access),它的速度要比LinkedList快。LinkedList中的get方法是按照順序從列表的一端開始檢查,直到另外一端。對LinkedList而言,訪問列表中的某個指定元素沒有更快的方法了。
          假設我們有一個很大的列表,它里面的元素已經排好序了,這個列表可能是ArrayList類型的也可能是LinkedList類型的,現在我們對這個列表來進行二分查找(binary search),比較列表是ArrayList和LinkedList時的查詢速度,看下面的程序:

          Java代碼 復制代碼 收藏代碼
          1. package com.mangocity.test;    
          2. import java.util.LinkedList;    
          3. import java.util.List;    
          4. import java.util.Random;    
          5. import java.util.ArrayList;    
          6. import java.util.Arrays;    
          7. import java.util.Collections;    
          8. public class TestList ...{    
          9.      public static final int N=50000;    
          10.   
          11.      public static List values;    
          12.   
          13.      static...{    
          14.          Integer vals[]=new Integer[N];    
          15.   
          16.          Random r=new Random();    
          17.   
          18.          for(int i=0,currval=0;i<N;i++)...{    
          19.              vals=new Integer(currval);    
          20.              currval+=r.nextInt(100)+1;    
          21.          }    
          22.   
          23.          values=Arrays.asList(vals);    
          24.      }    
          25.   
          26.      static long timeList(List lst)...{    
          27.          long start=System.currentTimeMillis();    
          28.          for(int i=0;i<N;i++)...{    
          29.              int index=Collections.binarySearch(lst, values.get(i));    
          30.              if(index!=i)    
          31.                  System.out.println("***錯誤***");    
          32.          }    
          33.          return System.currentTimeMillis()-start;    
          34.      }    
          35.      public static void main(String args[])...{    
          36.          System.out.println("ArrayList消耗時間:"+timeList(new ArrayList(values)));    
          37.          System.out.println("LinkedList消耗時間:"+timeList(new LinkedList(values)));    
          38.      }    
          39. }   

           
          我得到的輸出是:ArrayList消耗時間:15
                           LinkedList消耗時間:2596
          這個結果不是固定的,但是基本上ArrayList的時間要明顯小于LinkedList的時間。因此在這種情況下不宜用LinkedList。二分查找法使用的隨機訪問(random access)策略,而LinkedList是不支持快速的隨機訪問的。對一個LinkedList做隨機訪問所消耗的時間與這個list的大小是成比例的。而相應的,在ArrayList中進行隨機訪問所消耗的時間是固定的。
          這是否表明ArrayList總是比LinkedList性能要好呢?這并不一定,在某些情況下LinkedList的表現要優于ArrayList,有些算法在LinkedList中實現時效率更高。比方說,利用Collections.reverse方法對列表進行反轉時,其性能就要好些。
          看這樣一個例子,加入我們有一個列表,要對其進行大量的插入和刪除操作,在這種情況下LinkedList就是一個較好的選擇。請看如下一個極端的例子,我們重復的在一個列表的開端插入一個元素:

          Java代碼 復制代碼 收藏代碼
          1. package com.mangocity.test;    
          2.   
          3. import java.util.*;    
          4. public class ListDemo {    
          5.      static final int N=50000;    
          6.      static long timeList(List list){    
          7.      long start=System.currentTimeMillis();    
          8.      Object o = new Object();    
          9.      for(int i=0;i<N;i++)    
          10.          list.add(0, o);    
          11.      return System.currentTimeMillis()-start;    
          12.      }    
          13.      public static void main(String[] args) {    
          14.          System.out.println("ArrayList耗時:"+timeList(new ArrayList()));    
          15.          System.out.println("LinkedList耗時:"+timeList(new LinkedList()));    
          16.      }    
          17. }   

           這時我的輸出結果是:ArrayList耗時:2463

           


                                     LinkedList耗時:15
          這和前面一個例子的結果截然相反,當一個元素被加到ArrayList的最開端時,所有已經存在的元素都會后移,這就意味著數據移動和復制上的開銷。相反的,將一個元素加到LinkedList的最開端只是簡單的未這個元素分配一個記錄,然后調整兩個連接。在LinkedList的開端增加一個元素的開銷是固定的,而在ArrayList的開端增加一個元素的開銷是與ArrayList的大小成比例的。


          二.空間復雜度
          在LinkedList中有一個私有的內部類,定義如下:

          Java代碼 復制代碼 收藏代碼
          1. private static class Entry {    
          2.          Object element;    
          3.          Entry next;    
          4.          Entry previous;    
          5.      }   

           
          每個Entry對象reference列表中的一個元素,同時還有在LinkedList中它的上一個元素和下一個元素。一個有1000個元素的LinkedList對象將有1000個鏈接在一起的Entry對象,每個對象都對應于列表中的一個元素。這樣的話,在一個LinkedList結構中將有一個很大的空間開銷,因為它要存儲這1000個Entity對象的相關信息。
          ArrayList使用一個內置的數組來存儲元素,這個數組的起始容量是10.當數組需要增長時,新的容量按如下公式獲得:新容量=(舊容量*3)/2+1,也就是說每一次容量大概會增長50%。這就意味著,如果你有一個包含大量元素的ArrayList對象,那么最終將有很大的空間會被浪費掉,這個浪費是由ArrayList的工作方式本身造成的。如果沒有足夠的空間來存放新的元素,數組將不得不被重新進行分配以便能夠增加新的元素。對數組進行重新分配,將會導致性能急劇下降。如果我們知道一個ArrayList將會有多少個元素,我們可以通過構造方法來指定容量。我們還可以通過trimToSize方法在ArrayList分配完畢之后去掉浪費掉的空間。


          三.總結
          ArrayList和LinkedList在性能上各有優缺點,都有各自所適用的地方,總的說來可以描述如下:
          1.對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部數組中增加一項,指向所添加的元素,偶爾可能會導致對數組重新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry對象。


          2.在ArrayList的中間插入或刪除一個元素意味著這個列表中剩余的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。


          3.LinkedList不支持高效的隨機元素訪問。


          4.ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間


          可以這樣說:當操作是在一列數據的后面添加數據而不是在前面或中間,并且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能;當你的操作是在一列數據的前面或中間添加或刪除數據,并且按照順序訪問其中的元素時,就應該使用LinkedList了。

           

          posted @ 2012-11-14 17:50 云云 閱讀(4153) | 評論 (0)編輯 收藏

               摘要: Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。        一、當兩個并發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。  ...  閱讀全文

          posted @ 2012-11-10 10:41 云云 閱讀(278) | 評論 (0)編輯 收藏

          /**
           * 
           
          */

          package com.test;

          import java.util.ArrayList;
          import java.util.Iterator;
          import java.util.List;
          import java.util.concurrent.CopyOnWriteArrayList;

          /**
           * 
          @author hello_yun
           *
           
          */

          public class ListOperation
          {

              
          /**
               * 
          @param args
               
          */

              
          public static void main(String[] args)
              
          {
                  List
          <Integer> list1 = new ArrayList<Integer>();
                  List
          <Integer> list2 = new CopyOnWriteArrayList<Integer>();
                  list1.add(
          1);
                  list1.add(
          2);
                  list1.add(
          3);
                  
                  list2.add(
          3);
                  list2.add(
          4);
                  
          //        try
          //        {
          //            for(Integer in : list1){
          //                list1.remove(in);//直接循環 刪除對象會拋異常
          //            }
          //        } catch (Exception e)
          //        {
          //            System.out.println("list1 size : "+list1.size());
          //            System.out.println("循環list1 異常 : "+e);
          //        }
                  
                  
                  
          for(Integer in : list2){
                      list2.remove(in);
                      System.out.println(
          "list2 : "+list2.size());
                  }

                  
                   
                  
                  list1.add(
          1);
                  list1.add(
          2);
                  
                  list2.add(
          3);
                  list2.add(
          4);
                  
                  
          for (Iterator iterator = list1.iterator(); iterator.hasNext();)
                  
          {
                      iterator.next();
                      iterator.remove();
                  }

                  
                  
                  
          try
                  
          {
                      
          for (Iterator iterator = list2.iterator(); iterator.hasNext();)
                      
          {
                          iterator.next();
                          iterator.remove();
                      }


                  }
           catch (Exception e)
                  
          {
                      System.out.println(
          "copyOnWriteArrayList remove : "+ e);
                  }

                  
                  
          //-------------這種方式 不會拋異常 -------------------------
                  try
                  
          {
                      
          for(int i=0;i<list1.size();i++){
                          list1.remove(i);
                      }


                  }
           catch (Exception e)
                  
          {
                      System.out.println(
          "list1 size : "+list1.size());
                      System.out.println(
          "循環list1 異常 : "+e);
                  }


              }


          }


          使用 copyOnWriteArrayList時 ,通過 list.remove()方法是安全的 但是使用iterator.remove是會拋異常的
          查看copyOnWriteArrayList源碼 會發現 iterator.remove方法的實現是直接拋異常的
                  /**
                   * Not supported. Always throws UnsupportedOperationException.
                   * @throws UnsupportedOperationException always; <tt>remove</tt>
                   *         is not supported by this iterator.
                   */
                  public void remove() {
                      throw new UnsupportedOperationException();
                  }

          但是通過ArrayList實現時, list.remove會拋異常 java.util.ConcurrentModificationException,
          但是 ArrayList的 iterator.remove不會拋異常



          posted @ 2012-11-01 18:09 云云 閱讀(3842) | 評論 (1)編輯 收藏

          僅列出標題
          共12頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
          主站蜘蛛池模板: 沁阳市| 铁力市| 和静县| 寿阳县| 富平县| 慈利县| 恩施市| 保亭| 鱼台县| 孙吴县| 南阳市| 屏边| 辛集市| 莒南县| 临海市| 巴塘县| 华蓥市| 三穗县| 廉江市| 宜章县| 湖口县| 洮南市| 布尔津县| 隆林| 昂仁县| 微山县| 赤城县| 合山市| 彭泽县| 集安市| 藁城市| 晴隆县| 青浦区| 营山县| 呼玛县| 商河县| 富民县| 桑日县| 滦平县| 金门县| 潍坊市|