2013年6月20日


          版權(quán)信息: 可以任意轉(zhuǎn)載, 轉(zhuǎn)載時(shí)請(qǐng)務(wù)必以超鏈接形式標(biāo)明文章原文出處, 即下面的聲明.

          原文出處:http://blog.chenlb.com/2009/06/java-classloader-architecture.html

          jvm classLoader architecture:

          1. Bootstrap ClassLoader/啟動(dòng)類加載器 
            主要負(fù)責(zé)jdk_home/lib目錄下的核心 api 或 -Xbootclasspath 選項(xiàng)指定的jar包裝入工作。
          2. Extension ClassLoader/擴(kuò)展類加載器 
            主要負(fù)責(zé)jdk_home/lib/ext目錄下的jar包或 -Djava.ext.dirs 指定目錄下的jar包裝入工作。
          3. System ClassLoader/系統(tǒng)類加載器 
            主要負(fù)責(zé)java -classpath/-Djava.class.path所指的目錄下的類與jar包裝入工作。
          4. User Custom ClassLoader/用戶自定義類加載器(java.lang.ClassLoader的子類) 
            在程序運(yùn)行期間, 通過java.lang.ClassLoader的子類動(dòng)態(tài)加載class文件, 體現(xiàn)java動(dòng)態(tài)實(shí)時(shí)類裝入特性。

          類加載器的特性:

          1. 每個(gè)ClassLoader都維護(hù)了一份自己的名稱空間, 同一個(gè)名稱空間里不能出現(xiàn)兩個(gè)同名的類。
          2. 為了實(shí)現(xiàn)java安全沙箱模型頂層的類加載器安全機(jī)制, java默認(rèn)采用了 " 雙親委派的加載鏈 " 結(jié)構(gòu)。
          classloader-architecture

          classloader-architecture

          classloader-class-diagram

          classloader-class-diagram

          類圖中, BootstrapClassLoader是一個(gè)單獨(dú)的java類, 其實(shí)在這里, 不應(yīng)該叫他是一個(gè)java類。因?yàn)椋呀?jīng)完全不用java實(shí)現(xiàn)了。它是在jvm啟動(dòng)時(shí), 就被構(gòu)造起來的, 負(fù)責(zé)java平臺(tái)核心庫。

          自定義類加載器加載一個(gè)類的步驟

          classloader-load-class

          classloader-load-class

          ClassLoader 類加載邏輯分析, 以下邏輯是除 BootstrapClassLoader 外的類加載器加載流程:

          1. // 檢查類是否已被裝載過  
          2. Class c = findLoadedClass(name);  
          3. if (c == null ) {  
          4.      // 指定類未被裝載過  
          5.      try {  
          6.          if (parent != null ) {  
          7.              // 如果父類加載器不為空, 則委派給父類加載  
          8.              c = parent.loadClass(name, false );  
          9.          } else {  
          10.              // 如果父類加載器為空, 則委派給啟動(dòng)類加載加載  
          11.              c = findBootstrapClass0(name);  
          12.          }  
          13.      } catch (ClassNotFoundException e) {  
          14.          // 啟動(dòng)類加載器或父類加載器拋出異常后, 當(dāng)前類加載器將其  
          15.          // 捕獲, 并通過findClass方法, 由自身加載  
          16.          c = findClass(name);  
          17.      }  
          18. }  

          線程上下文類加載器
          java默認(rèn)的線程上下文類加載器是 系統(tǒng)類加載器(AppClassLoader)。

          1. // Now create the class loader to use to launch the application  
          2. try {  
          3.     loader = AppClassLoader.getAppClassLoader(extcl);  
          4. catch (IOException e) {  
          5.     throw new InternalError(  
          6. "Could not create application class loader" );  
          7. }   
          8.   
          9. // Also set the context class loader for the primordial thread.  
          10. Thread.currentThread().setContextClassLoader(loader);  

          以上代碼摘自sun.misc.Launch的無參構(gòu)造函數(shù)Launch()。

          使用線程上下文類加載器, 可以在執(zhí)行線程中, 拋棄雙親委派加載鏈模式, 使用線程上下文里的類加載器加載類.
          典型的例子有, 通過線程上下文來加載第三方庫jndi實(shí)現(xiàn), 而不依賴于雙親委派.
          大部分java app服務(wù)器(jboss, tomcat..)也是采用contextClassLoader來處理web服務(wù)。
          還有一些采用 hotswap 特性的框架, 也使用了線程上下文類加載器, 比如 seasar (full stack framework in japenese).

          線程上下文從根本解決了一般應(yīng)用不能違背雙親委派模式的問題.
          使java類加載體系顯得更靈活.

          隨著多核時(shí)代的來臨, 相信多線程開發(fā)將會(huì)越來越多地進(jìn)入程序員的實(shí)際編碼過程中. 因此,
          在編寫基礎(chǔ)設(shè)施時(shí), 通過使用線程上下文來加載類, 應(yīng)該是一個(gè)很好的選擇。

          當(dāng)然, 好東西都有利弊. 使用線程上下文加載類, 也要注意, 保證多根需要通信的線程間的類加載器應(yīng)該是同一個(gè),
          防止因?yàn)椴煌念惣虞d器, 導(dǎo)致類型轉(zhuǎn)換異常(ClassCastException)。

          為什么要使用這種雙親委托模式呢?

          1. 因?yàn)檫@樣可以避免重復(fù)加載,當(dāng)父親已經(jīng)加載了該類的時(shí)候,就沒有必要子ClassLoader再加載一次。
          2. 考慮到安全因素,我們?cè)囅胍幌拢绻皇褂眠@種委托模式,那我們就可以隨時(shí)使用自定義的String來動(dòng)態(tài)替代java核心api中定義類型,這樣會(huì)存在非常大的安全隱患,而雙親委托的方式,就可以避免這種情況,因?yàn)镾tring已經(jīng)在啟動(dòng)時(shí)被加載,所以用戶自定義類是無法加載一個(gè)自定義的ClassLoader。

          java動(dòng)態(tài)載入class的兩種方式:

          1. implicit隱式,即利用實(shí)例化才載入的特性來動(dòng)態(tài)載入class
          2. explicit顯式方式,又分兩種方式:
            1. java.lang.Class的forName()方法
            2. java.lang.ClassLoader的loadClass()方法

          用Class.forName加載類

          Class.forName使用的是被調(diào)用者的類加載器來加載類的。
          這種特性, 證明了java類加載器中的名稱空間是唯一的, 不會(huì)相互干擾。
          即在一般情況下, 保證同一個(gè)類中所關(guān)聯(lián)的其他類都是由當(dāng)前類的類加載器所加載的。

          1. public static Class forName(String className)  
          2.      throws ClassNotFoundException {  
          3.      return forName0(className, true , ClassLoader.getCallerClassLoader());  
          4. }   
          5.   
          6. /** Called after security checks have been made. */  
          7. private static native Class forName0(String name, boolean initialize,  
          8. ClassLoader loader)  
          9.      throws ClassNotFoundException;  

          上面中 ClassLoader.getCallerClassLoader 就是得到調(diào)用當(dāng)前forName方法的類的類加載器

          static塊在什么時(shí)候執(zhí)行?

          • 當(dāng)調(diào)用forName(String)載入class時(shí)執(zhí)行,如果調(diào)用ClassLoader.loadClass并不會(huì)執(zhí)行.forName(String,false,ClassLoader)時(shí)也不會(huì)執(zhí)行.
          • 如果載入Class時(shí)沒有執(zhí)行static塊則在第一次實(shí)例化時(shí)執(zhí)行.比如new ,Class.newInstance()操作
          • static塊僅執(zhí)行一次

          各個(gè)java類由哪些classLoader加載?

          • java類可以通過實(shí)例.getClass.getClassLoader()得知
          • 接口由AppClassLoader(System ClassLoader,可以由ClassLoader.getSystemClassLoader()獲得實(shí)例)載入
          • ClassLoader類由bootstrap loader載入

          NoClassDefFoundError和ClassNotFoundException

          • NoClassDefFoundError:當(dāng)java源文件已編譯成.class文件,但是ClassLoader在運(yùn)行期間在其搜尋路徑load某個(gè)類時(shí),沒有找到.class文件則報(bào)這個(gè)錯(cuò)
          • ClassNotFoundException:試圖通過一個(gè)String變量來創(chuàng)建一個(gè)Class類時(shí)不成功則拋出這個(gè)異常
          posted @ 2013-06-20 10:25 陳睿 閱讀(367) | 評(píng)論 (1)編輯 收藏

          2012年7月3日

          一:quartz簡(jiǎn)介
                 OpenSymphony 的Quartz提供了一個(gè)比較完美的任務(wù)調(diào)度解決方案。
                 Quartz 是個(gè)開源的作業(yè)調(diào)度框架,定時(shí)調(diào)度器,為在 Java 應(yīng)用程序中進(jìn)行作業(yè)調(diào)度提供了簡(jiǎn)單卻強(qiáng)大的機(jī)制。
                 Quartz中有兩個(gè)基本概念:作業(yè)和觸發(fā)器。作業(yè)是能夠調(diào)度的可執(zhí)行任務(wù),觸發(fā)器提供了對(duì)作業(yè)的調(diào)度

          二:quartz spring配置詳解
          •  為什么不適用java.util.Timer結(jié)合java.util.TimerTask 
                  1.主要的原因,適用不方便,特別是制定具體的年月日時(shí)分的時(shí)間,而quartz使用類似linux上的cron配置,很方便的配置每隔時(shí)間執(zhí)行觸發(fā)。

                  2.其次性能的原因,使用jdk自帶的Timer不具備多線程,而quartz采用線程池,性能上比timer高出很多。


          •    詳解quartz在spring里面的配置
              在spring里主要分為兩種使用方式:第一種,也是目前使用最多的方式,spring提供的MethodInvokingJobDetailFactoryBean代理類,通過雷利類直接調(diào)用任務(wù)類的某個(gè)函數(shù);第二種,程序里實(shí)現(xiàn)quartz接口,quartz通過該接口進(jìn)行調(diào)度。

                主要講解通過spring提供的代理類MethodInvokingJobDetailFactoryBean

                  1.業(yè)務(wù)邏輯類:業(yè)務(wù)邏輯是獨(dú)立的,本身就與quartz解耦的,并沒有深入進(jìn)去,這對(duì)業(yè)務(wù)來講是很好的一個(gè)方式。

                                  public class  TestJobTask{
               

                /**
                 *業(yè)務(wù)邏輯處理
                 
          */
                  public void   service(){
                      /**業(yè)務(wù)邏輯*/
                          ..
                  }

          }
                 
              2.增加一個(gè)線程池
              <!-- 線程執(zhí)行器配置,用于任務(wù)注冊(cè) -->
          <bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
           <property name="corePoolSize" value="10" />
           <property name="maxPoolSize" value="100" />
           <property name="queueCapacity" value="500" />
          </bean>

            3.定義業(yè)務(wù)邏輯類

              <!-- 業(yè)務(wù)對(duì)象 -->
          <bean id="testJobTask" class="com.mike.scheduling.TestJobTask" />


              4.增加quartz調(diào)用業(yè)務(wù)邏輯

              <!-- 調(diào)度業(yè)務(wù) -->
          <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
           <property name="targetObject" ref="testJobTask" />
           <property name="targetMethod" value="service" />
          </bean>

              5.增加調(diào)用的觸發(fā)器,觸發(fā)的時(shí)間,有兩種方式:

               第一種觸發(fā)時(shí)間,采用類似linux的cron,配置時(shí)間的表示發(fā)出豐富  
            <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
           <property name="jobDetail" ref="jobDetail" />
           <property name="cronExpression" value="10 0/1 * * * ?" />
          </bean>
            Cron表達(dá)式“10 */1 * * * ?”意為:從10秒開始,每1分鐘執(zhí)行一次 
            
              第二種,采用比較簡(jiǎn)話的方式,申明延遲時(shí)間和間隔時(shí)間
            <bean id="taskTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
           <property name="jobDetail" ref="jobDetail" />
           <property name="startDelay" value="10000" />
           <property name="repeatInterval" value="60000" />
          </bean>
            延遲10秒啟動(dòng),然后每隔1分鐘執(zhí)行一次 

              6.開始調(diào)用

                <!-- 設(shè)置調(diào)度 -->
          <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
           <property name="triggers">
            <list>
             <ref bean="cronTrigger" />
            </list>
           </property>
           <property name="taskExecutor" ref="executor" />
          </bean>

             7.結(jié)束:?jiǎn)?dòng)容器即可,已經(jīng)將spring和quartz結(jié)合完畢。

              Cron常用的表達(dá)式
              "0 0 12 * * ?" 每天中午12點(diǎn)觸發(fā)
          "0 15 10 ? * *" 每天上午10:15觸發(fā)
          "0 15 10 * * ?" 每天上午10:15觸發(fā)
          "0 15 10 * * ? *" 每天上午10:15觸發(fā)
          "0 15 10 * * ? 2005" 2005年的每天上午10:15觸發(fā)
          "0 * 14 * * ?" 在每天下午2點(diǎn)到下午2:59期間的每1分鐘觸發(fā)
          "0 0/5 14 * * ?" 在每天下午2點(diǎn)到下午2:55期間的每5分鐘觸發(fā)
          "0 0/5 14,18 * * ?" 在每天下午2點(diǎn)到2:55期間和下午6點(diǎn)到6:55期間的每5分鐘觸發(fā)
          "0 0-5 14 * * ?" 在每天下午2點(diǎn)到下午2:05期間的每1分鐘觸發(fā)
          "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44觸發(fā)
          "0 15 10 ? * MON-FRI" 周一至周五的上午10:15觸發(fā)
          "0 15 10 15 * ?" 每月15日上午10:15觸發(fā)
          "0 15 10 L * ?" 每月最后一日的上午10:15觸發(fā)
          "0 15 10 ? * 6L" 每月的最后一個(gè)星期五上午10:15觸發(fā) 
          "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一個(gè)星期五上午10:15觸發(fā)
          "0 15 10 ? * 6#3" 每月的第三個(gè)星期五上午10:15觸發(fā)

          三:quartz原理

              根據(jù)上面spring的配置,我們就比較清楚quartz的內(nèi)部情況,下面我們主要詳解配置涉及到的每個(gè)點(diǎn)
              1.我們先從最后一個(gè)步驟看起,SchedulerFactoryBean ,scheduler的工廠實(shí)現(xiàn),里面可以生產(chǎn)出對(duì)應(yīng)的多個(gè)jobDetail和trigger,每個(gè)jobDetail對(duì)應(yīng)trigger代表一個(gè)任務(wù)
                   Quartz的SchedulerFactory是標(biāo)準(zhǔn)的工廠類,不太適合在Spring環(huán)境下使用。此外,為了保證Scheduler能夠感知 Spring容器的生命周期,完成自動(dòng)啟動(dòng)和關(guān)閉的操作,必須讓Scheduler和Spring容器的生命周期相關(guān)聯(lián)。以便在Spring容器啟動(dòng)后, Scheduler自動(dòng)開始工作,而在Spring容器關(guān)閉前,自動(dòng)關(guān)閉Scheduler。為此,Spring提供 SchedulerFactoryBean,這個(gè)FactoryBean大致?lián)碛幸韵碌墓δ埽?nbsp;
               1)以更具Bean風(fēng)格的方式為Scheduler提供配置信息; 
               2)讓Scheduler和Spring容器的生命周期建立關(guān)聯(lián),相生相息; 
               3)通過屬性配置部分或全部代替Quartz自身的配置文件。 
            2.jobDetail,表示一個(gè)可執(zhí)行的業(yè)務(wù)調(diào)用
            
            3.trigger:調(diào)度的時(shí)間計(jì)劃,什么時(shí)候,每隔多少時(shí)間可執(zhí)行等時(shí)間計(jì)劃

            4.ThreadPoolTaskExecutor,線程池,用來并行執(zhí)行每個(gè)對(duì)應(yīng)的job,提高效率,這也是上面提到不推薦使用jdk自身timer的一個(gè)很重要的原因
          posted @ 2012-07-03 14:42 陳睿 閱讀(3092) | 評(píng)論 (2)編輯 收藏

          2012年3月30日

          之前有接觸過hadoop,但都比較淺顯,對(duì)立面的東東不是很清楚!
          打算后面在hadoop上花時(shí)間把里面的內(nèi)容,好好學(xué)學(xué),這篇博客將在后面陸續(xù)更新hadoop學(xué)習(xí)筆記。
          posted @ 2012-03-30 10:14 陳睿 閱讀(362) | 評(píng)論 (0)編輯 收藏

          2012年3月12日

          一:基本原理
              主要是要實(shí)現(xiàn)網(wǎng)絡(luò)之間的通訊,網(wǎng)絡(luò)通信需要做的就是將流從一臺(tái)計(jì)算機(jī)傳輸?shù)搅硗庖慌_(tái)計(jì)算機(jī),基于傳輸協(xié)議和網(wǎng)絡(luò)IO來實(shí)現(xiàn),其中傳輸協(xié)議比較出名的有http、 tcp、udp等等,http、tcp、udp都是在基于Socket概念上為某類應(yīng)用場(chǎng)景而擴(kuò)展出的傳輸協(xié)議,網(wǎng)絡(luò)IO,主要有bio、nio、aio 三種方式,所有的分布式應(yīng)用通訊都基于這個(gè)原理而實(shí)現(xiàn)。

          二:實(shí)踐
          在分布式服務(wù)框架中,一個(gè)最基礎(chǔ)的問題就是遠(yuǎn)程服務(wù)是怎么通訊的,在Java領(lǐng)域中有很多可實(shí)現(xiàn)遠(yuǎn)程通訊的技術(shù):RMI、MINA、ESB、Burlap、Hessian、SOAP、EJB和JMS
          既然引入出了這么多技術(shù),那我們就順道深入挖掘下去,了解每個(gè)技術(shù)框架背后的東西:
          1.首先看RMI
               RMI主要包含如下內(nèi)容: 
               遠(yuǎn)程服務(wù)的接口定義 
                ·遠(yuǎn)程服務(wù)接口的具體實(shí)現(xiàn) 
                ·樁(Stub)和框架(Skeleton)文件 
                ·一個(gè)運(yùn)行遠(yuǎn)程服務(wù)的服務(wù)器 
                ·一個(gè)RMI命名服務(wù),它允許客戶端去發(fā)現(xiàn)這個(gè)遠(yuǎn)程服務(wù) 
                ·文件的提供者(一個(gè)HTTP或者FTP服務(wù)器) 
                ·一個(gè)需要這個(gè)遠(yuǎn)程服務(wù)的客戶端程序 
              
              來看下基于RMI的一次完整的遠(yuǎn)程通信過程的原理:
              1)客戶端發(fā)起請(qǐng)求,請(qǐng)求轉(zhuǎn)交至RMI客戶端的stub類;
              2)stub類將請(qǐng)求的接口、方法、參數(shù)等信息進(jìn)行序列化;
              3)基于tcp/ip將序列化后的流傳輸至服務(wù)器端;
              4)服務(wù)器端接收到流后轉(zhuǎn)發(fā)至相應(yīng)的skelton類;
              5)skelton類將請(qǐng)求的信息反序列化后調(diào)用實(shí)際的處理類;
              6)處理類處理完畢后將結(jié)果返回給skelton類;
              7)Skelton類將結(jié)果序列化,通過tcp/ip將流傳送給客戶端的stub;
              8)stub在接收到流后反序列化,將反序列化后的Java Object返回給調(diào)用者。

               RMI應(yīng)用級(jí)協(xié)議內(nèi)容:
          1、傳輸?shù)臉?biāo)準(zhǔn)格式是什么?
                是Java ObjectStream。
          2、怎么樣將請(qǐng)求轉(zhuǎn)化為傳輸?shù)牧鳎?/div>
                基于Java串行化機(jī)制將請(qǐng)求的java object信息轉(zhuǎn)化為流。
          3、怎么接收和處理流?
                根據(jù)采用的協(xié)議啟動(dòng)相應(yīng)的監(jiān)聽端口,當(dāng)有流進(jìn)入后基于Java串行化機(jī)制將流進(jìn)行反序列化,并根據(jù)RMI協(xié)議獲取到相應(yīng)的處理對(duì)象信息,進(jìn)行調(diào)用并處理,處理完畢后的結(jié)果同樣基于java串行化機(jī)制進(jìn)行返回。
          4、傳輸協(xié)議是?
                tcp/ip。

          原理講了,開始實(shí)踐:
          創(chuàng)建RMI程序的6個(gè)步驟: 
          1、定義一個(gè)遠(yuǎn)程接口的接口,該接口中的每一個(gè)方法必須聲明它將產(chǎn)生一個(gè)RemoteException異常。 
          2、定義一個(gè)實(shí)現(xiàn)該接口的類。 
          3、使用RMIC程序生成遠(yuǎn)程實(shí)現(xiàn)所需的殘根和框架。 
          4、創(chuàng)建一個(gè)服務(wù)器,用于發(fā)布2中寫好的類。 
          5. 創(chuàng)建一個(gè)客戶程序進(jìn)行RMI調(diào)用。 
          6、啟動(dòng)rmiRegistry并運(yùn)行自己的遠(yuǎn)程服務(wù)器和客戶程序     
              
           
          1)首先創(chuàng)建遠(yuǎn)程接口:
           /**
           * 遠(yuǎn)程接口
           * 
           * @author mike
           *
           * 
          @since 2012-3-14
           
          */
          public interface Hello extends Remote {
              /**
               * 測(cè)試rmi 
               * 
               * 
          @return   hello
               * 
          @throws RemoteException
               
          */
              public String hello()throws RemoteException;
          }
                 
               2)創(chuàng)建接口實(shí)現(xiàn)
                  package com.gewara.rmi;

          import java.rmi.RemoteException;
          import java.rmi.server.UnicastRemoteObject;

          /**
           * 遠(yuǎn)程接口實(shí)現(xiàn)
           * 
           * 
          @author mike
           *
           * 
          @since 2012-3-14
           
          */
          public class HelloImpl extends UnicastRemoteObject implements Hello {

              /**
               * seria id
               
          */
              private static final long serialVersionUID = -7931720891757437009L;

              protected HelloImpl() throws RemoteException {
                  super();
              }

              /**
               * hello實(shí)現(xiàn)
               * 
               * 
          @return hello world
               * 
          @throws RemoteException
               
          */
              public String hello() throws RemoteException {
                  return "hello world";
              }

          }

                 3)創(chuàng)建服務(wù)器端
                  package com.gewara.rmi;

          import java.rmi.Naming;
          import java.rmi.registry.LocateRegistry;

          public class Server {
              
              private static final String RMI_URL="rmi://192.168.2.89:10009/server";
              
              /**
               * RMI Server
               
          */
              public Server() {  
                  try {  
                      //創(chuàng)建遠(yuǎn)程對(duì)象
                      Hello hello=new HelloImpl();
                      
                      //啟動(dòng)注冊(cè)表
                      LocateRegistry.createRegistry(10009);
                      
                      //將名稱綁定到對(duì)象
                      Naming.bind(RMI_URL, hello);
                      
                  } catch (Exception e) {  
                      e.printStackTrace();  
                  }  
              }  
              
              /**
               * 
          @param args
               
          */
              public static void main(String[] args) {
                  new Server();

              }

          }

                  4)創(chuàng)建客服端
                  package com.gewara.rmi;

          import java.rmi.Naming;

          public class Client {

              private static final String RMI_URL="rmi://192.168.2.89:10009/server";
              /**
               * 
          @param args
               
          */
              public static void main(String[] args) {
                   try {  
                             String result=((Hello)Naming.lookup(RMI_URL)).hello();
                          System.out.println(result);  
                      } catch (Exception e) {  
                          e.printStackTrace();  
                      }  
              }

          }

              5)先啟動(dòng)服務(wù)器端,然后再啟動(dòng)客戶端
                 顯示結(jié)果:hello world

          由于涉及到的內(nèi)容比較多,打算每一篇里講一個(gè)遠(yuǎn)程通訊框架,繼續(xù)詳解RMI
              
          三:詳解RMI內(nèi)部原理
          1. RMI基本結(jié)構(gòu):包含兩個(gè)獨(dú)立的程序,服務(wù)器和客戶端,服務(wù)器創(chuàng)建多個(gè)遠(yuǎn)程對(duì)象,讓遠(yuǎn)程對(duì)象能夠被引用,等待客戶端調(diào)用這些遠(yuǎn)程對(duì)象的方法。客戶端從服務(wù)器獲取到一個(gè)或則多個(gè)遠(yuǎn)程對(duì)象的引用,然后調(diào)用遠(yuǎn)程對(duì)象方法,主要涉及到RMI接口、回調(diào)等技術(shù)。

          2.RMI回調(diào):服務(wù)器提供遠(yuǎn)程對(duì)象引用供客戶端調(diào)用,客戶端主動(dòng)調(diào)用服務(wù)器,如果服務(wù)器主動(dòng)打算調(diào)用客戶端,這就叫回調(diào)。

          3.命名遠(yuǎn)程對(duì)象:客戶端通過一個(gè)命名或則一個(gè)查找服務(wù)找到遠(yuǎn)程服務(wù),遠(yuǎn)程服務(wù)包含Java的命名和查找接口(Java Naming and Directory Interface)JNDI
          RMI提供了一種服務(wù):RMI注冊(cè)rmiregistry,默認(rèn)端口:1099,主機(jī)提供遠(yuǎn)程服務(wù),接受服務(wù),啟動(dòng)注冊(cè)服務(wù)的命令:start rmiregistry
          客戶端使用一個(gè)靜態(tài)類Naming到達(dá)RMI注冊(cè)處,通過方法lookup()方法,客戶來詢問注冊(cè)。
          posted @ 2012-03-12 09:57 陳睿 閱讀(2297) | 評(píng)論 (2)編輯 收藏

          2012年2月29日

          一:spring概要
              簡(jiǎn)單來說,Spring是一個(gè)輕量級(jí)的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器框架。
              
          控制反轉(zhuǎn)——Spring通過一種稱作控制反轉(zhuǎn)(IoC)的技術(shù)促進(jìn)了松耦合。當(dāng)應(yīng)用了IoC,一個(gè)對(duì)象依賴的其它對(duì)象會(huì)通過被動(dòng)的方式傳遞進(jìn)來,而不是這個(gè)對(duì)象自己創(chuàng)建或者查找依賴對(duì)象。你可以認(rèn)為IoC與JNDI相反——不是對(duì)象從容器中查找依賴,而是容器在對(duì)象初始化時(shí)不等對(duì)象請(qǐng)求就主動(dòng)將依賴傳遞給它。
            ◆面向切面——Spring提供了面向切面編程的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級(jí)服務(wù)(例如審計(jì)(auditing)和事務(wù)(transaction)管理)進(jìn)行內(nèi)聚性的開發(fā)。應(yīng)用對(duì)象只實(shí)現(xiàn)它們應(yīng)該做的——完成業(yè)務(wù)邏輯——僅此而已。它們并不負(fù)責(zé)(甚至是意識(shí))其它的系統(tǒng)級(jí)關(guān)注點(diǎn),例如日志或事務(wù)支持。
            ◆容器——Spring包含并管理應(yīng)用對(duì)象的配置和生命周期,在這個(gè)意義上它是一種容器,你可以配置你的每個(gè)bean如何被創(chuàng)建——基于一個(gè)可配置原型(prototype),你的bean可以創(chuàng)建一個(gè)單獨(dú)的實(shí)例或者每次需要時(shí)都生成一個(gè)新的實(shí)例——以及它們是如何相互關(guān)聯(lián)的。然而,Spring不應(yīng)該被混同于傳統(tǒng)的重量級(jí)的EJB容器,它們經(jīng)常是龐大與笨重的,難以使用。
            ◆框架——Spring可以將簡(jiǎn)單的組件配置、組合成為復(fù)雜的應(yīng)用。在Spring中,應(yīng)用對(duì)象被聲明式地組合,典型地是在一個(gè)XML文件里。Spring也提供了很多基礎(chǔ)功能(事務(wù)管理、持久化框架集成等等),將應(yīng)用邏輯的開發(fā)留給了你。
            所有Spring的這些特征使你能夠編寫更干凈、更可管理、并且更易于測(cè)試的代碼。它們也為Spring中的各種模塊提供了基礎(chǔ)支持。

          二:spring的整個(gè)生命周期
              首先說一下spring的整個(gè)初始化過程,web應(yīng)用中創(chuàng)建spring容器有兩種方式:
              第一種:在web.xml里直接配置spring容器,servletcontextlistener
              第二種:通過load-on-startup servlet實(shí)現(xiàn)。
              主要就說一下第一種方式:
              spring提供了ServletContextListener的實(shí)現(xiàn)類ContextLoaderListener,該類作為listener使用,在創(chuàng)建時(shí)自動(dòng)查找WEB-INF目錄下的applicationContext.xml,該文件是默認(rèn)查找的,如果只有一個(gè)就不需要配置初始化xml參數(shù),如果需要配置,設(shè)置contextConfigLocation為application的xml文件即可。可以好好閱讀一下ContextLoaderListener的源代碼,就可以很清楚的知道spring的整個(gè)加載過程。
              spring容器的初始化代碼如下:
              /**
               * Initialize the root web application context.
               */
              
          public void contextInitialized(ServletContextEvent event) {
                  
          this.contextLoader = createContextLoader();
                  
          if (this.contextLoader == null) {
                      
          this.contextLoader = this;
                  }
                  
          this.contextLoader.initWebApplicationContext(event.getServletContext());//contextLoader初始化web應(yīng)用容器

              }
              繼續(xù)分析initWebApplicationContext做了什么事情:
              

              
          /**
               * Initialize Spring's web application context for the given servlet context,
               * according to the "{
          @link #CONTEXT_CLASS_PARAM contextClass}" and
               * "{
          @link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
               * 
          @param servletContext current servlet context
               * 
          @return the new WebApplicationContext
               * 
          @see #CONTEXT_CLASS_PARAM
               * 
          @see #CONFIG_LOCATION_PARAM
               
          */
              
          public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
                
          //首先創(chuàng)建一個(gè)spring的父容器,類似根節(jié)點(diǎn)root容器,而且只能是一個(gè),如果已經(jīng)創(chuàng)建,拋出對(duì)應(yīng)的異常
                  
          if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
                      
          throw new IllegalStateException(
                              
          "Cannot initialize context because there is already a root application context present - " +
                              
          "check whether you have multiple ContextLoader* definitions in your web.xml!");
                  }

                  Log logger 
          = LogFactory.getLog(ContextLoader.class);
                  servletContext.log(
          "Initializing Spring root WebApplicationContext");
                  
          if (logger.isInfoEnabled()) {
                      logger.info(
          "Root WebApplicationContext: initialization started");
                  }
                  
          long startTime = System.currentTimeMillis();

                  
          try {
                      
          // Determine parent for root web application context, if any.
                      ApplicationContext parent = loadParentContext(servletContext);//創(chuàng)建通過web.xml配置的父容器            
          具體里面的代碼是怎么實(shí)現(xiàn)的,就不在這里進(jìn)行詳解了
          // Store context in local instance variable, to guarantee that
                      
          // it is available on ServletContext shutdown.
                      this.context = createWebApplicationContext(servletContext, parent);//主要的創(chuàng)建過程都在改方法內(nèi),可以自己去看源代碼
                      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, 
          this.context);
                      
          //把spring初始好的容器加載到servletcontext內(nèi),相當(dāng)于servletcontext包含webapplicationcontext
                      ClassLoader ccl 
          = Thread.currentThread().getContextClassLoader();
                      
          if (ccl == ContextLoader.class.getClassLoader()) {
                          currentContext 
          = this.context;
                      }
                      
          else if (ccl != null) {
                          currentContextPerThread.put(ccl, 
          this.context);
                      }

                      
          if (logger.isDebugEnabled()) {
                          logger.debug(
          "Published root WebApplicationContext as ServletContext attribute with name [" +
                                  WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 
          + "]");
                      }
                      
          if (logger.isInfoEnabled()) {
                          
          long elapsedTime = System.currentTimeMillis() - startTime;
                          logger.info(
          "Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
                      }

                      
          return this.context;
                  }
                  
          catch (RuntimeException ex) {
                      logger.error(
          "Context initialization failed", ex);
                      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
                      
          throw ex;
                  }
                  
          catch (Error err) {
                      logger.error(
          "Context initialization failed", err);
                      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
                      
          throw err;
                  }
              }
              
              看到這里基本已經(jīng)清楚了整個(gè)spring容器的加載過程,如果還想了解更加深入,請(qǐng)查看我紅色標(biāo)注的方法體。

              其次再說一下spring的IOC和AOP使用的場(chǎng)景,由于原理大家都很清楚了,那就說一下它們使用到的地方:
             

              IOC使用的場(chǎng)景:
                  管理bean的依賴關(guān)系,目前主流的電子商務(wù)網(wǎng)站基本都采用spring管理業(yè)務(wù)層代碼的依賴關(guān)系,包括:淘寶,支付寶,阿里巴巴,百度等公司。
                  
          posted @ 2012-02-29 14:45 陳睿 閱讀(1623) | 評(píng)論 (0)編輯 收藏

          2012年2月27日

          一:struts2概要
              以WebWork優(yōu)秀設(shè)計(jì)思想為核心,吸收了struts1的部分優(yōu)點(diǎn)。

          二:struts2詳解
              主要就是詳解struts2與struts1之間的區(qū)別,以及為什么要采用webwork重新設(shè)計(jì)新框架,以及吸收了struts1的哪部分優(yōu)點(diǎn)。
              首先將區(qū)別:
          •     最大的區(qū)別是與servlet成功解耦,不在依賴容器來初始化HttpServletRequest和HttpServletResponse
              struts1里依賴的核心控制器為ActionServlet而struts2依賴ServletDispatcher,一個(gè)是servlet一個(gè)是filter,正是采用了filter才不至于和servlet耦合,所有的數(shù)據(jù) 都是通過攔截器來實(shí)現(xiàn),如下圖顯示:
              

          •     web層表現(xiàn)層的豐富,struts2已經(jīng)可以使用jsp、velocity、freemarker
          •     線程模式方面:struts1的action是單例模式而且必須是線程安全或同步的,是struts2的action對(duì)每一個(gè)請(qǐng)求都產(chǎn)生一個(gè)新的實(shí)例,因此沒有線程安全問       題。
          •     封裝請(qǐng)求參數(shù):是struts1采用ActionForm封裝請(qǐng)求參數(shù),都必須繼承ActionForm基類,而struts2通過bean的屬性封裝,大大降低了耦合。
          •     類型轉(zhuǎn)換:struts1封裝的ActionForm都是String類型,采用Commons- Beanutils進(jìn)行類型轉(zhuǎn)換,每個(gè)類一個(gè)轉(zhuǎn)換器;struts2采用OGNL進(jìn)行類型轉(zhuǎn)       換,支持基本數(shù)據(jù)類型和封裝類型的自動(dòng)轉(zhuǎn)換。
          •     數(shù)據(jù)校驗(yàn):struts1在ActionForm中重寫validate方法;struts2直接重寫validate方法,直接在action里面重寫即可,不需要繼承任何基類,實(shí)際的調(diào)用順序是,validate()-->execute(),會(huì)在執(zhí)行execute之前調(diào)用validate,也支持xwork校驗(yàn)框架來校驗(yàn)。
              其次,講一下為什么要采用webwork來重新設(shè)計(jì)struts2
                    
          首先的從核心控制器談起,struts2的FilterDispatcher,這里我們知道是一個(gè)filter而不是一個(gè)servlet,講到這里很多人還不是很清楚web.xml里它們之間的聯(lián)系,先簡(jiǎn)短講一下它們的加載順序,context-param(應(yīng)用范圍的初始化參數(shù))-->listener(監(jiān)聽?wèi)?yīng)用端的任何修改通知)-->filter(過濾)-->servlet。
              filter在執(zhí)行servlet之間就以及調(diào)用了,所以才有可能解脫完全依賴servlet的局面,那我們來看看這個(gè)filter做了什么事情:
              /**
               * Process an action or handle a request a static resource.
               * <p/>
               * The filter tries to match the request to an action mapping.
               * If mapping is found, the action processes is delegated to the dispatcher's serviceAction method.
               * If action processing fails, doFilter will try to create an error page via the dispatcher.
               * <p/>
               * Otherwise, if the request is for a static resource,
               * the resource is copied directly to the response, with the appropriate caching headers set.
               * <p/>
               * If the request does not match an action mapping, or a static resource page,
               * then it passes through.
               *
               * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
               
          */
              
          public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

                  HttpServletRequest request 
          = (HttpServletRequest) req;
                  HttpServletResponse response 
          = (HttpServletResponse) res;
                  ServletContext servletContext 
          = getServletContext();

                  String timerKey 
          = "FilterDispatcher_doFilter: ";
                  
          try {

                      
          // FIXME: this should be refactored better to not duplicate work with the action invocation
                      ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
                      ActionContext ctx 
          = new ActionContext(stack.getContext());
                      ActionContext.setContext(ctx);

                      UtilTimerStack.push(timerKey);
                      request 
          = prepareDispatcherAndWrapRequest(request, response);
                      ActionMapping mapping;
                      
          try {
                          mapping 
          = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
                      } 
          catch (Exception ex) {
                          log.error(
          "error getting ActionMapping", ex);
                          dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
                          
          return;
                      }

                      
          if (mapping == null) {
                          
          // there is no action in this request, should we look for a static resource?
                          String resourcePath = RequestUtils.getServletPath(request);

                          
          if ("".equals(resourcePath) && null != request.getPathInfo()) {
                              resourcePath 
          = request.getPathInfo();
                          }

                          
          if (staticResourceLoader.canHandle(resourcePath)) {
                              staticResourceLoader.findStaticResource(resourcePath, request, response);
                          } 
          else {
                              
          // this is a normal request, let it pass through
                              chain.doFilter(request, response);
                          }
                          
          // The framework did its job here
                          return;
                      }

                      dispatcher.serviceAction(request, response, servletContext, mapping);
          //過濾用戶請(qǐng)求,攔截器執(zhí)行,把對(duì)應(yīng)的action請(qǐng)求轉(zhuǎn)到業(yè)務(wù)action執(zhí)行        } 

          finally {
                      
          try {
                          ActionContextCleanUp.cleanUp(req);
                      } 
          finally {
                          UtilTimerStack.pop(timerKey);
                      }
                  }
              }
              對(duì)應(yīng)的action參數(shù)由攔截器獲取。
              解耦servlet是struts2采用webwork思路的最重要的一個(gè)原因,也迎合了整個(gè)技術(shù)的一個(gè)發(fā)展方向,解耦一直貫穿于整個(gè)框架。
                  
          posted @ 2012-02-27 17:07 陳睿 閱讀(1664) | 評(píng)論 (2)編輯 收藏

          JVM specification對(duì)JVM內(nèi)存的描述

          首先我們來了解JVM specification中的JVM整體架構(gòu)。如下圖:

           


              
          主要包括兩個(gè)子系統(tǒng)和兩個(gè)組件: Class loader(類裝載器) 子系統(tǒng),Execution engine(執(zhí)行引擎) 子系統(tǒng);Runtime data area (運(yùn)行時(shí)數(shù)據(jù)區(qū)域)組件, Native interface(本地接口)組件。
               Class loader
          子系統(tǒng)的作用 :根據(jù)給定的全限定名類名( java.lang.Object)來裝載class文件的內(nèi)容到 Runtime data area中的method area(方法區(qū)域)Javsa程序員可以extends java.lang.ClassLoader類來寫自己的Class loader
                Execution engine
          子系統(tǒng)的作用 :執(zhí)行classes中的指令。任何JVM specification實(shí)現(xiàn)(JDK)的核心是Execution engine 換句話說:Sun JDK IBMJDK好壞主要取決于他們各自實(shí)現(xiàn)的Execution  engine的好壞。每個(gè)運(yùn)行中的線程都有一個(gè)Execution engine的實(shí)例。
               Native interface
          組件 :與native libraries交互,是其它編程語言交互的接口。 
               Runtime data area
          組件:這個(gè)組件就是JVM中的內(nèi)存

          • 運(yùn)行時(shí)數(shù)據(jù)組件的詳解介紹:
              

          Runtime data area 主要包括五個(gè)部分:Heap (堆), Method Area(方法區(qū)域), Java Stack(java的棧), Program Counter(程序計(jì)數(shù)器), Native method stack(本地方法棧)。Heap 和Method Area是被所有線程的共享使用的;而Java stack, Program counter 和Native method stack是以線程為粒度的,每個(gè)線程獨(dú)自擁有。

          Heap
          Java程序在運(yùn)行時(shí)創(chuàng)建的所有類實(shí)或數(shù)組都放在同一個(gè)堆中。
          而一個(gè)Java虛擬實(shí)例中只存在一個(gè)堆空間,因此所有線程都將共享這個(gè)堆。每一個(gè)java程序獨(dú)占一個(gè)JVM實(shí)例,因而每個(gè)java程序都有它自己的堆空間,它們不會(huì)彼此干擾。但是同一java程序的多個(gè)線程都共享著同一個(gè)堆空間,就得考慮多線程訪問對(duì)象(堆數(shù)據(jù))的同步問題。 (這里可能出現(xiàn)的異常java.lang.OutOfMemoryError: Java heap space)

          JVM堆一般又可以分為以下三部分:

          Ø Perm

          Perm代主要保存class,method,filed對(duì)象,這部門的空間一般不會(huì)溢出,除非一次性加載了很多的類,不過在涉及到熱部署的應(yīng)用服務(wù)器的時(shí)候,有時(shí)候會(huì)遇到java.lang.OutOfMemoryError : PermGen space 的錯(cuò)誤,造成這個(gè)錯(cuò)誤的很大原因就有可能是每次都重新部署,但是重新部署后,類的class沒有被卸載掉,這樣就造成了大量的class對(duì)象保存在了perm中,這種情況下,一般重新啟動(dòng)應(yīng)用服務(wù)器可以解決問題。

          Ø Tenured

          Tenured區(qū)主要保存生命周期長(zhǎng)的對(duì)象,一般是一些老的對(duì)象,當(dāng)一些對(duì)象在Young復(fù)制轉(zhuǎn)移一定的次數(shù)以后,對(duì)象就會(huì)被轉(zhuǎn)移到Tenured區(qū),一般如果系統(tǒng)中用了application級(jí)別的緩存,緩存中的對(duì)象往往會(huì)被轉(zhuǎn)移到這一區(qū)間。

          Ø Young

          Young區(qū)被劃分為三部分,Eden區(qū)和兩個(gè)大小嚴(yán)格相同的Survivor區(qū),其中Survivor區(qū)間中,某一時(shí)刻只有其中一個(gè)是被使用的,另外一個(gè)留做垃圾收集時(shí)復(fù)制對(duì)象用,在Young區(qū)間變滿的時(shí)候,minor GC就會(huì)將存活的對(duì)象移到空閑的Survivor區(qū)間中,根據(jù)JVM的策略,在經(jīng)過幾次垃圾收集后,任然存活于Survivor的對(duì)象將被移動(dòng)到Tenured區(qū)間。


          Method area
          在Java虛擬機(jī)中,被裝載的class的信息存儲(chǔ)在Method area的內(nèi)存中。
          當(dāng)虛擬機(jī)裝載某個(gè)類型時(shí),它使用類裝載器定位相應(yīng)的class文件,然后讀入這個(gè)class文件內(nèi)容并把它傳輸?shù)教摂M機(jī)中。緊接著虛擬機(jī)提取其中的類型信息,并將這些信息存儲(chǔ)到方法區(qū)。該類型中的類(靜態(tài))變量同樣也存儲(chǔ)在方法區(qū)中。與Heap 一樣,method area是多線程共享的,因此要考慮多線程訪問的同步問題。比如,假設(shè)同時(shí)兩個(gè)線程都企圖訪問一個(gè)名為L(zhǎng)ava的類,而這個(gè)類還沒有內(nèi)裝載入虛擬機(jī),那么,這時(shí)應(yīng)該只有一個(gè)線程去裝載它,而另一個(gè)線程則只能等待。 (這里可能出現(xiàn)的異常java.lang.OutOfMemoryError: PermGen full)

          Java stack
                 Java stack以幀為單位保存線程的運(yùn)行狀態(tài)。虛擬機(jī)只會(huì)直接對(duì)Java stack執(zhí)行兩種操作:以幀為單位的壓棧或出棧。
          每當(dāng)線程調(diào)用一個(gè)方法的時(shí)候,就對(duì)當(dāng)前狀態(tài)作為一個(gè)幀保存到java stack中(壓棧);當(dāng)一個(gè)方法調(diào)用返回時(shí),從java stack彈出一個(gè)幀(出棧)。棧的大小是有一定的限制,這個(gè)可能出現(xiàn)StackOverFlow問題。 下面的程序可以說明這個(gè)問題。

           

          public class TestStackOverFlow {
           
               public static void main(String[] args) {
           
                      Recursive r = new Recursive();
                      r.doit(10000);
                      // Exception in thread "main" java.lang.StackOverflowError
               }
           
          }
           
          class Recursive {
           
               public int doit(int t) {
                      if (t <= 1) {
                              return 1;
                      }
                      return t + doit(t - 1);
               }
           
          }

           

          Program counter
          每個(gè)運(yùn)行中的Java程序,每一個(gè)線程都有它自己的PC寄存器,也是該線程啟動(dòng)時(shí)創(chuàng)建的。PC寄存器的內(nèi)容總是指向下一條將被執(zhí)行指令的餓&ldquo;地址&rdquo;,這里的&ldquo;地址&rdquo;可以是一個(gè)本地指針,也可以是在方法區(qū)中相對(duì)應(yīng)于該方法起始指令的偏移量。

          Native method stack
          對(duì)于一個(gè)運(yùn)行中的Java程序而言,它還能會(huì)用到一些跟本地方法相關(guān)的數(shù)據(jù)區(qū)。當(dāng)某個(gè)線程調(diào)用一個(gè)本地方法時(shí),它就進(jìn)入了一個(gè)全新的并且不再受虛擬機(jī)限制的世界。本地方法可以通過本地方法接口來訪問虛擬機(jī)的運(yùn)行時(shí)數(shù)據(jù)區(qū),不止與此,它還可以做任何它想做的事情。比如,可以調(diào)用寄存器,或在操作系統(tǒng)中分配內(nèi)存等。總之,本地方法具有和JVM相同的能力和權(quán)限。 (這里出現(xiàn)JVM無法控制的內(nèi)存溢出問題native heap OutOfMemory )

          JVM提供了相應(yīng)的參數(shù)來對(duì)內(nèi)存大小進(jìn)行配置。



          正如上面描述,JVM中堆被分為了3個(gè)大的區(qū)間,同時(shí)JVM也提供了一些選項(xiàng)對(duì)Young,Tenured的大小進(jìn)行控制。

          Ø Total Heap 

          -Xms :指定了JVM初始啟動(dòng)以后初始化內(nèi)存

          -Xmx:指定JVM堆得最大內(nèi)存,在JVM啟動(dòng)以后,會(huì)分配-Xmx參數(shù)指定大小的內(nèi)存給JVM,但是不一定全部使用,JVM會(huì)根據(jù)-Xms參數(shù)來調(diào)節(jié)真正用于JVM的內(nèi)存

          -Xmx -Xms之差就是三個(gè)Virtual空間的大小

          Ø Young Generation

          -XX:NewRatio=8意味著tenured  young的比值81,這樣eden+2*survivor=1/9

          堆內(nèi)存

          -XX:SurvivorRatio=32意味著eden和一個(gè)survivor的比值是321,這樣一個(gè)Survivor就占Young區(qū)的1/34.

          -Xmn 參數(shù)設(shè)置了年輕代的大小

          Ø Perm Generation

          -XX:PermSize=16M -XX:MaxPermSize=64M

          Thread Stack

          -XX:Xss=128K

           


          posted @ 2012-02-27 15:35 陳睿 閱讀(528) | 評(píng)論 (1)編輯 收藏

          2012年2月24日

          數(shù)據(jù)庫端性能非常低
          •     優(yōu)化數(shù)據(jù)庫服務(wù)器端的配置參數(shù)
          •     應(yīng)用服務(wù)器端數(shù)據(jù)連接池的配置參數(shù)修改
          •     應(yīng)用服務(wù)器端的sql審核,建立更好的索引以及修改不好的sql語句:關(guān)聯(lián)表過多,查詢的數(shù)據(jù)量過大,表設(shè)計(jì)不合理等
          •     應(yīng)用服務(wù)器端拆解過大的表,分為多張表,甚至把一個(gè)數(shù)據(jù)庫分為多個(gè)數(shù)據(jù)庫
          •     數(shù)據(jù)庫服務(wù)器端拆解為讀/寫分離,Master/Slave方式,一臺(tái)寫主機(jī)對(duì)應(yīng)兩臺(tái)或則多臺(tái)讀的備用機(jī)器
          應(yīng)用服務(wù)器端
          •     訪問壓力過大,1臺(tái)機(jī)器不能承受,該為多臺(tái)機(jī)器,應(yīng)用服務(wù)器配置為集群模式
              
              
          posted @ 2012-02-24 16:17 陳睿 閱讀(230) | 評(píng)論 (0)編輯 收藏

          2012年2月21日

          1.    多線程概念:
                 線程是指進(jìn)程中的一個(gè)執(zhí)行流程,一個(gè)進(jìn)程中可以運(yùn)行多個(gè)線程。比如java.exe進(jìn)程中可以運(yùn)行很多線程。線程總是屬于某個(gè)進(jìn)程,進(jìn)程中的多個(gè)線程共享進(jìn)程的內(nèi)存。
          •     多線程的實(shí)現(xiàn)方式和啟動(dòng)
          •     多線程是依靠什么方式解決資源競(jìng)爭(zhēng)
          •     多線程的各種狀態(tài)以及優(yōu)先級(jí)
          •     多線程的暫停方式
           2.    多線程詳解
                  1)多線程的實(shí)現(xiàn)方式和啟動(dòng):
          •       繼承Thread和是實(shí)現(xiàn)Runnable接口,重寫run方法
          •       啟動(dòng)只有一種方式:通過start方法,虛擬機(jī)會(huì)調(diào)用run方法

                 2) 多線程依靠什么解決資源競(jìng)爭(zhēng)
          •        鎖機(jī)制:分為對(duì)象鎖和類鎖,在多個(gè)線程調(diào)用的情況,每個(gè)對(duì)象鎖都是唯一的,只有獲取了鎖才能調(diào)用synchronized方法
          •        synchronize同步:分為同步方法和同步方法塊
          •        什么時(shí)候獲取鎖:每次調(diào)用到synchronize方法,這個(gè)時(shí)候去獲取鎖資源,如果線程獲取到鎖則別的線程只有等到同步方法介紹后,釋放鎖后,別的線程        才能繼續(xù)使用
                  3)線程的幾種狀態(tài)
          •        主要分為:新狀態(tài)(還沒有調(diào)用start方法),可執(zhí)行狀態(tài)(調(diào)用start方法),阻塞狀態(tài),死亡狀態(tài)
                  默認(rèn)優(yōu)先級(jí)為normal(5),優(yōu)先級(jí)數(shù)值在1-10之間
           4) 多線程的暫停方式

          •     sleep:睡眠單位為毫秒
          •     wait,waitAll,notify,notifyAll,wait等待,只有通過wait或者waitAll喚醒
          •     yield:cpu暫時(shí)停用
          •     join
          posted @ 2012-02-21 15:32 陳睿 閱讀(1429) | 評(píng)論 (0)編輯 收藏
          1. HashSet概要
          •     采用HashMap存儲(chǔ),key直接存取值,value存儲(chǔ)一個(gè)object
          •     存儲(chǔ)的key值是唯一的
          •      HashSet中元素的順序是隨機(jī)的,包括添加(add())和輸出都是無序的

            代碼就不具體詳解了,主要就是通過封裝HashMap組成。

          posted @ 2012-02-21 11:37 陳睿 閱讀(1104) | 評(píng)論 (0)編輯 收藏
          僅列出標(biāo)題  下一頁

          導(dǎo)航

          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          統(tǒng)計(jì)

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 华池县| 涡阳县| 方山县| 南充市| 依兰县| 扎囊县| 荔浦县| 上杭县| 上蔡县| 正镶白旗| 关岭| 东乡县| 儋州市| 黑龙江省| 罗田县| 白银市| 岳阳县| 汝阳县| 荣成市| 平利县| 楚雄市| 会同县| 余干县| 淮滨县| 汝城县| 宝丰县| 霍林郭勒市| 肥城市| 无极县| 壤塘县| 炎陵县| 韶关市| 阿坝| 惠州市| 九龙城区| 商洛市| 三门县| 揭西县| 扶风县| 泽库县| 南陵县|