<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    2006年10月30日

    struts2 基礎(chǔ)

    1. action extends ActionSupport abstract class, because it already provide some default operation(input, createErrorMessage).
    2. property is set by reflect to action, and pass to jsp(jsp is filled with these properties, jsp is a servlet, what it returned to user is HTML file)
    3. static validate happened in action method(override ActionSupport method), dynamic validation happened in action layer.
    4. change dynamic property file value in this way : thankyou=Thank you for registerling %{personBean.firstName}, Resource file can be deployed in action layer, package layer and global layer
    5. exception can be configured in bellow way:  <global-exception-mappings>
       <exception-mapping exception="org.apache.struts.register.exceptions.SecurityBreachException" result="securityerror" />
        <exception-mapping exception="java.lang.Exception" result="error" />
         </global-exception-mappings>
       
        <global-results>
              <result name="securityerror">/securityerror.jsp</result>
         <result name="error">/error.jsp</result>
         </global-results>
    6. Wildcard Method Selection: flexible but not useful(<action name="*Person" class="org.apache.struts.tutorials.wildcardmethod.action.PersonAction" method="{1}">)
    7. integrate spring & struts 2 way: use spring plugin, main point is who to maintain action creation(spring || action), better choice is spring, you can enjoy great function of spring.
    8. Add Convention Plugin to so that you can use annotation
    9. intercepter can be configured in action level and package level.

    posted @ 2011-03-29 12:07 Sheldon Sun 閱讀(238) | 評論 (0)編輯 收藏

    轉(zhuǎn):用Spring快速開發(fā)jms應(yīng)用(JBOSS服務(wù)器)

    異步進(jìn)程通信是面向服務(wù)架構(gòu)(SOA)一個(gè)重要的組成部分,因?yàn)槠髽I(yè)里很多系統(tǒng)通信,特別是與外部組織間的通信,實(shí)質(zhì)上都是異步的。Java消息服務(wù)(JMS)是用于編寫使用異步消息傳遞的JEE應(yīng)用程序的API。傳統(tǒng)的使用JMS API進(jìn)行消息傳遞的實(shí)現(xiàn)包括多個(gè)步驟,例如JNDI查詢隊(duì)列連接工廠和Queue資源,在實(shí)際發(fā)送和接收消息前創(chuàng)建一個(gè)JMS會話。

       Spring框架則簡化了使用JEE組件(包括JMS)的任務(wù)。它提供的模板機(jī)制隱藏了典型的JMS實(shí)現(xiàn)的細(xì)節(jié),這樣開發(fā)人員可以集中精力放在處理消息的實(shí)際工作中,而不用擔(dān)心如何去創(chuàng)建,訪問或清除JMS資源。

       本文將對Spring JMS API作一個(gè)概述,并通過一個(gè)運(yùn)行在JBoss MQ服務(wù)器上的web例程來介紹如何使用Spring JMS API來異步處理(發(fā)送和接收)消息。我將通過傳統(tǒng)JMS實(shí)現(xiàn)和Spring JMS實(shí)現(xiàn)兩者間的比較,來展示使用Spring JMS處理消息是如何的簡單和靈活。

    異步消息傳遞和面向服務(wù)架構(gòu)

      在現(xiàn)實(shí)中,大多數(shù)web請求都是同步處理的。例如,當(dāng)用戶要登入一個(gè)網(wǎng)站,首先輸入用戶名和密碼,然后服務(wù)器驗(yàn)證登錄合法性。如果驗(yàn)證成功,程序?qū)⒃试S該用戶進(jìn)入網(wǎng)站。這里,登錄請求在從客戶端接收以后被即時(shí)處理了。信用卡驗(yàn)證是另一個(gè)同步處理的例子;只有服務(wù)器證實(shí)輸入的信用卡號是有效的,同時(shí)客戶在帳戶上有足夠的存款,客戶才被允許繼續(xù)操作。但是讓我們思考一下在順序處理系統(tǒng)上的支付結(jié)算步驟。一旦系統(tǒng)證實(shí)該用戶信用卡的信息是準(zhǔn)確的,并且在帳戶上有足夠的資金,就不必等到所有的支付細(xì)節(jié)落實(shí)、轉(zhuǎn)賬完成。支付結(jié)算可以異步方式進(jìn)行,這樣客戶可以繼續(xù)進(jìn)行核查操作。

       需要比典型同步請求耗費(fèi)更長時(shí)間的請求,可以使用異步處理。另一個(gè)異步處理的例子是,在本地貸款處理程序中,提交至自動承銷系統(tǒng)(AUS)的信用請求處理過程。當(dāng)借方提交貸款申請后,抵押公司會向AUS發(fā)送請求,以獲取信用歷史記錄。由于這個(gè)請求要求得到全面而又詳細(xì)的信用報(bào)告,包括借方現(xiàn)今和過去的帳戶,最近的付款和其他財(cái)務(wù)資料,服務(wù)器需要耗費(fèi)較長的時(shí)間(幾小時(shí)或著有時(shí)甚至是幾天)來對這些請求作出響應(yīng)。客戶端程序(應(yīng)用)要與服務(wù)器連接并耗費(fèi)如此長的時(shí)間來等待結(jié)果,這是毫無意義的。因此通信應(yīng)該是異步發(fā)生的;也就是,一旦請求被提交,它就被放置在隊(duì)列中,同時(shí)客戶端與服務(wù)器斷開連接。然后AUS服務(wù)從指定的隊(duì)列中選出請求進(jìn)行處理,并將處理得到的消息放置在另一個(gè)消息隊(duì)列里。最后,客戶端程序從這個(gè)隊(duì)列中選出處理結(jié)果,緊接著處理這個(gè)信用歷史數(shù)據(jù)。

    JMS

       如果您使用過JMS代碼,您會發(fā)現(xiàn)它與JDBC或JCA很像。它所包含的樣本代碼創(chuàng)建或JMS資源對象回溯,使得每一次您需要寫一個(gè)新類來發(fā)送和接收消息時(shí),都具有更好的代碼密集性和重復(fù)性。以下序列顯示了傳統(tǒng)JMS實(shí)現(xiàn)所包括的步驟:

    1. 創(chuàng)建JNDI初始上下文(context)。
    2. 從JNDI上下文獲取一個(gè)隊(duì)列連接工廠。
    3. 從隊(duì)列連接工廠中獲取一個(gè)Quene。
    4. 創(chuàng)建一個(gè)Session對象。
    5. 創(chuàng)建一個(gè)發(fā)送者(sender)或接收者(receiver)對象。
    6. 使用步驟5創(chuàng)建的發(fā)送者或接收者對象發(fā)送或接收消息。
    7. 處理完消息后,關(guān)閉所有JMS資源。

    您可以看到,步驟6是處理消息的唯一地方。其他步驟都只是管理與實(shí)際業(yè)務(wù)要求無關(guān)的JMS資源,但是開發(fā)人員必須編寫并維護(hù)這些額外步驟的代碼。

    Spring JMS

       Spring框架提供了一個(gè)模板機(jī)制來隱藏Java APIs的細(xì)節(jié)。JEE開發(fā)人員可以使用JDBCTemplate和JNDITemplate類來分別訪問后臺數(shù)據(jù)庫和JEE資源(數(shù)據(jù)源,連接池)。JMS也不例外。Spring提供JMSTemplate類,因此開發(fā)人員不用為一個(gè)JMS實(shí)現(xiàn)去編寫樣本代碼。接下來是在開發(fā)JMS應(yīng)用程序時(shí)Spring所具有一些的優(yōu)勢。

    1. 提供JMS抽象API,簡化了訪問目標(biāo)(隊(duì)列或主題)和向指定目標(biāo)發(fā)布消息時(shí)JMS的使用。
    2. JEE開發(fā)人員不需要關(guān)心JMS不同版本(例如JMS 1.0.2與JMS 1.1)之間的差異。
    3. 開發(fā)人員不必專門處理JMS異常,因?yàn)镾pring為所有JMS異常提供了一個(gè)未經(jīng)檢查的異常,并在JMS代碼中重新拋出。

    示例程序

            說明:因?yàn)橹皇菫榱搜菔救绾问褂胹pring編寫jms的應(yīng)用,所以本例沒有什么實(shí)際用途。

            程序功能:MessageProducer.java根據(jù)一用戶信息產(chǎn)生一個(gè)消息發(fā)送到 JMS Provider;由MessageConsumer.java接收。

    1.在Jboss里配置XML文件創(chuàng)建一個(gè)新的JMS provider。
    打開位于%JBOSS_HOME%server\default\deploy\jms文件夾下的jbossmq-destinations-service.xml文件,加入以下代碼片斷:
     <!--  Register User Send/Receive Queue  -->
     <mbean code="org.jboss.mq.server.jmx.Queue"
       name="jboss.mq.destination:service=Queue,name=registerUserQueue">
       <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
     </mbean>
     <!--  Register User Send/Receive Topic  -->
     <mbean code="org.jboss.mq.server.jmx.Topic"
      name="jboss.mq.destination:service=Topic,name=registerUserTopic">
       <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
     </mbean>
    2.在spring的配置文件中配置JMS組件的具體細(xì)節(jié)。
     (1)JNDI上下文是取得JMS資源的起始位置,因此首先我們要配置JNDI模板:
        <!-- JNDI上下文(它是取得JMS資源的起始位置) -->
       <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
        <property name="environment">
         <props>
          <prop key="java.naming.factory.initial">
           org.jnp.interfaces.NamingContextFactory
          </prop>
          <prop key="java.naming.provider.url">localhost</prop>
          <prop key="java.naming.factory.url.pkgs">
           org.jnp.interfaces:org.jboss.naming
          </prop>
         </props>
        </property>
       </bean>
       注意:此JNDI模板用到了org.jnp.interfaces.NamingContextFactory所以要把%JBOSS_HOME%\client下的jbossall-client.jar加到你的項(xiàng)目的classpath中。
    (2)配置連接工廠:
       <!-- JMS連接工廠 -->
         <bean id="jmsConnectionFactory"class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiTemplate">
         <ref bean="jndiTemplate" />
        </property>
        <property name="jndiName">
         <value>XAConnectionFactory</value>
        </property>
       </bean>
       注意:XAConnectionFactory這個(gè)JNDI名字是在%JBOSS_HOME%server\default\deploy\jms文件夾下的jms-ds.xml中定義的(它是由JBoss指定的)。
     (3)配置JmsTemplate組件。在例程中我們使用JmsTemplate102。同時(shí)使用defaultDestination屬性來指定JMS目標(biāo)。
      <!-- JMS模板配置 -->
      <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate102">
       <property name="connectionFactory" ref="jmsConnectionFactory" />
       <property name="defaultDestination" ref="destination" />
       <property name="pubSubDomain">
        <value>true</value>
       </property>
       <!-- 等待消息的時(shí)間(ms) -->
       <property name="receiveTimeout">
             <value>30000</value>
          </property>
      </bean>
      注意:如果使用topic-subscribe(主題訂閱)模式,該模板的pubSubDomain屬性值為true;若使用PToP(點(diǎn)對點(diǎn))模式,pubSubDomain屬性值為false或不配置該屬性。
     (4)定義一個(gè)JMS目標(biāo)來發(fā)送和接收消息:
      <bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
       <property name="jndiTemplate">
        <ref bean="jndiTemplate" />
       </property>
       <property name="jndiName">
        <value>topic/registerUserTopic</value>
       </property>
      </bean>
     (5)配置發(fā)送者和接收者組件:
      <!-- 消息發(fā)布者 -->
      <bean id="msgProducer" class="com.boco.jms.MessageProducer">
       <property name="jmsTemplate" ref="jmsTemplate" />
      </bean>
      <!-- 消息接收者 -->
      <bean id="msgConsumer" class="com.boco.jms.MessageConsumer">
       <property name="jmsTemplate" ref="jmsTemplate" />
      </bean>
    3.相應(yīng)的類:
     (1). User對象。
       /**
       *  User.java
       *  created on Jul 2, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.dto;
      
      import java.io.Serializable;
      
      /**
       * desc: 用戶信息 Bean
       * @author qiujy
       */
      public class User {
       private int id;
       private String username;
       private String password;
       private String email;
       
       public User(){}
       
       //以下為Getter,setter方法略
       ......
      }
      
     (2).消息生產(chǎn)者:
       /**
       *  MessageProducer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import javax.jms.JMSException;
      import javax.jms.MapMessage;
      import javax.jms.Message;
      import javax.jms.Session;
      
      import org.springframework.jms.core.JmsTemplate;
      import org.springframework.jms.core.MessageCreator;
      
      import com.boco.dto.User;
      
      /**
       * desc:消息生產(chǎn)者
       * @author qiujy
       *
       */
      public class MessageProducer {
       /** JMS模板 */
       private JmsTemplate jmsTemplate;
       
       public void setJmsTemplate(JmsTemplate jmsTemplate){
        this.jmsTemplate = jmsTemplate;
       }
       
       public void sendMessage(final User user){
        //調(diào)用模板的send來發(fā)送消息
        jmsTemplate.send(new MessageCreator(){
      
         public Message createMessage(Session session) throws JMSException {
          //構(gòu)造一個(gè)要發(fā)送的消息
          MapMessage message = session.createMapMessage();
           message.setInt("id", user.getId());
           message.setString("username", user.getUsername());
           message.setString("password", user.getPassword());
           message.setString("email", user.getEmail());
          System.out.println("send success!!");
          return message;
         }
        });
       }
      }
      
     (3).消息消費(fèi)者:
      /**
       *  MessageConsumer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import javax.jms.JMSException;
      import javax.jms.MapMessage;
      
      import org.springframework.jms.core.JmsTemplate;
      
      import com.boco.dto.User;
      
      /**
       * desc:消息消費(fèi)者
       * @author qiujy
       *
       */
      public class MessageConsumer {
       /** JMS模板 */
       private JmsTemplate jmsTemplate;
       
       public void setJmsTemplate(JmsTemplate jmsTemplate){
        this.jmsTemplate = jmsTemplate;
       }
       
       public User receiveMessage(){
        //參數(shù)為Destination的JNDI名字去掉前面的模式類型標(biāo)識
        //MapMessage msg = (MapMessage)jmsTemplate.receive("registerUserQueue");
        MapMessage msg = (MapMessage)jmsTemplate.receive("registerUserTopic");
        User user = new User();
        
        try {
         user.setId(msg.getInt("id"));
         user.setUsername(msg.getString("username"));
         user.setPassword(msg.getString("password"));
         user.setEmail(msg.getString("email"));
        } catch (JMSException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }
        
        return user;
       }
      }

     (4).測試用例:
       //======== 生產(chǎn)者測試用例 ===============
       /**
       *  TestMsgProducer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import junit.framework.TestCase;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      import com.boco.dto.User;
      
      /**
       * desc:
       * @author qiujy
       *
       */
      public class TestMsgProducer extends TestCase {
      
       private ApplicationContext context;
       /**
        * @param arg0
        */
       public TestMsgProducer(String arg0) {
        super(arg0);
        context = new ClassPathXmlApplicationContext("applicationContext_jms.xml");
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#setUp()
        */
       protected void setUp() throws Exception {
        super.setUp();
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#tearDown()
        */
       protected void tearDown() throws Exception {
        super.tearDown();
       }
      
       /**
        * Test method for {@link com.boco.jms.MessageProducer#sendMessage(com.boco.dto.User)}.
        */
       public void testSendMessage() {
        User user = new User();
        user.setId(132);
        user.setUsername("JMSTest");
        user.setPassword("password");
        user.setEmail("support@boco.com.cn");
        
        MessageProducer producer = (MessageProducer)context.getBean("msgProducer");
        
        producer.sendMessage(user);
        
       }
      
      }

      //============ 消費(fèi)者測試用例 ===============
      /**
       *  TestMsgConsumer.java
       *  created on Jul 22, 2006
       *  Copyrights 2006 BOCO,Inc. All rights reserved.
       */
      package com.boco.jms;
      
      import junit.framework.TestCase;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      import com.boco.dto.User;
      
      /**
       * desc:
       * @author qiujy
       *
       */
      public class TestMsgConsumer extends TestCase {
       private ApplicationContext context;
       /**
        * @param arg0
        */
       public TestMsgConsumer(String arg0) {
        super(arg0);
        context = new ClassPathXmlApplicationContext("applicationContext_jms.xml");
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#setUp()
        */
       protected void setUp() throws Exception {
        super.setUp();
       }
      
       /* (non-Javadoc)
        * @see junit.framework.TestCase#tearDown()
        */
       protected void tearDown() throws Exception {
        super.tearDown();
       }
      
       /**
        * Test method for {@link com.boco.jms.MessageConsumer#receiveMessage()}.
        */
       public void testReceiveMessage() {
        MessageConsumer consumer = (MessageConsumer)context.getBean("msgConsumer");
        User user = consumer.receiveMessage();
        assertNotNull(user);
        System.out.println( "id========" + user.getId()
            + "\nname======" + user.getUsername()
            + "\npassword==" + user.getPassword()
            + "\nemail=====" + user.getEmail());
       }
      
      }

    posted @ 2011-03-23 14:49 Sheldon Sun 閱讀(270) | 評論 (0)編輯 收藏

    concurrent

    AVA后臺程序設(shè)計(jì)及UTIL.CONCURRENT包的應(yīng)用


    摘要 : 在很多軟件項(xiàng)目中,JAVA語言常常被用來開發(fā)后臺服務(wù)程序。線程池技術(shù)是提高這類程序性能的一個(gè)重要手段。在實(shí)踐中,該技術(shù)已經(jīng)被廣泛的使用。本文首先 對設(shè)計(jì)后臺服務(wù)程序通常需要考慮的問題進(jìn)行了基本的論述,隨后介紹了JAVA線程池的原理、使用和其他一些相關(guān)問題,最后對功能強(qiáng)大的JAVA開放源碼線 程池包util.concurrent 在實(shí)際編程中的應(yīng)用進(jìn)行了詳細(xì)介紹。
    關(guān)鍵字: JAVA;線程池;后臺服務(wù)程序;util.concurrent



    1 引言
    在軟件項(xiàng)目開發(fā)中,許多后臺服務(wù)程序的處理動作流程都具有一個(gè)相同點(diǎn),就是:接受客戶端發(fā)來的請求,對請求進(jìn)行一些相關(guān)的處理,最后將處理結(jié)果返回給客戶 端。這些請求的來源和方式可能會各不相同,但是它們常常都有一個(gè)共同點(diǎn):數(shù)量巨大,處理時(shí)間短。這類服務(wù)器在實(shí)際應(yīng)用中具有較大的普遍性,如web服務(wù) 器,短信服務(wù)器,DNS服務(wù)器等等。因此,研究如何提高此類后臺程序的性能,如何保證服務(wù)器的穩(wěn)定性以及安全性都具有重要的實(shí)用價(jià)值。

    2 后臺服務(wù)程序設(shè)計(jì)
    2.1 關(guān)于設(shè)計(jì)原型
    構(gòu)建服務(wù)器應(yīng)用程序的一個(gè)簡單的模型是:啟動一個(gè)無限循環(huán),循環(huán)里放一個(gè)監(jiān)聽線程監(jiān)聽某個(gè)地址端口。每當(dāng)一個(gè)請求到達(dá)就創(chuàng)建一個(gè)新線程,然后新線程為請求服務(wù),監(jiān)聽線程返回繼續(xù)監(jiān)聽。
    簡單舉例如下:
    import java.net.*;
    public class MyServer extends Thread{
    public void run(){
    try{
    ServerSocket server=null;
    Socket clientconnection=null;
    server = new ServerSocket(8008);//監(jiān)聽某地址端口對
    while(true){進(jìn)入無限循環(huán)
    clientconnection =server.accept();//收取請求
    new ServeRequest(clientconnection).start();//啟動一個(gè)新服務(wù)線程進(jìn)行服務(wù)
    ……
    }
    }catch(Exception e){
    System.err.println("Unable to start serve listen:"+e.getMessage());
    e.printStackTrace();
    }
    }
    }
    實(shí)際上,這只是個(gè)簡單的原型,如果試圖部署以這種方式運(yùn)行的服務(wù)器應(yīng)用程序,那么這種方法的嚴(yán)重不足就很明顯。
    首先,為每個(gè)請求創(chuàng)建一個(gè)新線程的開銷很大,為每個(gè)請求創(chuàng)建新線程的服務(wù)器在創(chuàng)建和銷毀線程上花費(fèi)的時(shí)間和消耗的系統(tǒng)資源, 往往有時(shí)候要比花在處理實(shí)際的用戶請求的時(shí)間和資源更多。在Java中更是如此,虛擬機(jī)將試圖跟蹤每一個(gè)對象,以便能夠在對象銷毀后進(jìn)行垃圾回收。所以提 高服務(wù)程序效率的一個(gè)手段就是盡可能減少創(chuàng)建和銷毀對象的次數(shù)。這樣綜合看來,系統(tǒng)的性能瓶頸就在于線程的創(chuàng)建開銷。
    其次,除了創(chuàng)建和銷毀線程的開銷之外,活動的線程也消耗系統(tǒng)資源。在一個(gè) JVM 里創(chuàng)建太多的線程可能會導(dǎo)致系統(tǒng)由于過度消耗內(nèi)存而用完內(nèi)存或“切換過度”。為了防止資源不足,服務(wù)器應(yīng)用程序需要一些辦法來限制任何給定時(shí)刻運(yùn)行的處理 線程數(shù)目,以防止服務(wù)器被“壓死”的情況發(fā)生。所以在設(shè)計(jì)后臺程序的時(shí)候,一般需要提前根據(jù)服務(wù)器的內(nèi)存、CPU等硬件情況設(shè)定一個(gè)線程數(shù)量的上限值。
    如果創(chuàng)建和銷毀線程的時(shí)間相對于服務(wù)時(shí)間占用的比例較大,那末假設(shè)在一個(gè)較短的時(shí)間內(nèi)有成千上萬的請求到達(dá),想象一下,服務(wù)器的時(shí)間和資源將會大量的花在 創(chuàng)建和銷毀線程上,而真正用于處理請求的時(shí)間卻相對較少,這種情況下,服務(wù)器性能瓶頸就在于創(chuàng)建和銷毀線程的時(shí)間。按照這個(gè)模型寫一個(gè)簡單的程序測試一下 即可看出,由于篇幅關(guān)系,此處略。如果把(服務(wù)時(shí)間/創(chuàng)建和銷毀線程的時(shí)間)作為衡量服務(wù)器性能的一個(gè)參數(shù),那末這個(gè)比值越大,服務(wù)器的性能就越高。
    應(yīng)此,解決此類問題的實(shí)質(zhì)就是盡量減少創(chuàng)建和銷毀線程的時(shí)間,把服務(wù)器的資源盡可能多地用到處理請求上來,從而發(fā)揮多線程的優(yōu)點(diǎn)(并發(fā)),避免多線程的缺點(diǎn)(創(chuàng)建和銷毀的時(shí)空開銷)。
    線程池為線程生命周期開銷問題和資源不足問題提供了解決方案。通過對多個(gè)任務(wù)重用線程,線程創(chuàng)建的開銷被分?jǐn)偟搅硕鄠€(gè)任務(wù)上。其好處是,因?yàn)樵谡埱蟮竭_(dá)時(shí) 線程已經(jīng)存在,所以無意中也消除了線程創(chuàng)建所帶來的延遲。這樣,就可以立即為請求服務(wù),使應(yīng)用程序響應(yīng)更快。而且,通過適當(dāng)?shù)卣{(diào)整線程池中的線程數(shù)目,也 就是當(dāng)請求的數(shù)目超過某個(gè)閾值時(shí),就強(qiáng)制其它任何新到的請求一直等待,直到獲得一個(gè)線程來處理為止,從而可以防止資源不足。

    3    JAVA線程池原理
    3.1 原理以及實(shí)現(xiàn)
    在實(shí)踐中,關(guān)于線程池的實(shí)現(xiàn)常常有不同的方法,但是它們的基本思路大都是相似的:服務(wù)器預(yù)先存放一定數(shù)目的“熱”的線程,并發(fā)程序需要使用線程的時(shí)候,從 服務(wù)器取用一條已經(jīng)創(chuàng)建好的線程(如果線程池為空則等待),使用該線程對請求服務(wù),使用結(jié)束后,該線程并不刪除,而是返回線程池中,以備復(fù)用,這樣可以避 免對每一個(gè)請求都生成和刪除線程的昂貴操作。
    一個(gè)比較簡單的線程池至少應(yīng)包含線程池管理器、工作線程、任務(wù)隊(duì)列、任務(wù)接口等部分。其中線程池管理器(ThreadPool Manager)的作用是創(chuàng)建、銷毀并管理線程池,將工作線程放入線程池中;工作線程是一個(gè)可以循環(huán)執(zhí)行任務(wù)的線程,在沒有任務(wù)時(shí)進(jìn)行等待;任務(wù)隊(duì)列的作 用是提供一種緩沖機(jī)制,將沒有處理的任務(wù)放在任務(wù)隊(duì)列中;任務(wù)接口是每個(gè)任務(wù)必須實(shí)現(xiàn)的接口,主要用來規(guī)定任務(wù)的入口、任務(wù)執(zhí)行完后的收尾工作、任務(wù)的執(zhí) 行狀態(tài)等,工作線程通過該接口調(diào)度任務(wù)的執(zhí)行。下面的代碼實(shí)現(xiàn)了創(chuàng)建一個(gè)線程池:
    public class ThreadPool
    { 
    private Stack threadpool = new Stack();
    private int poolSize;
    private int currSize=0;
    public void setSize(int n)
    { 
    poolSize = n;
    }
    public void run()
    {
    for(int i=0;i

    (發(fā)帖時(shí)間:2003-11-30 11:55:56) 
    ---岑心 J

    回復(fù)(1): 

    4.2    框架與結(jié)構(gòu)
    下面讓我們來看看util.concurrent的框架結(jié)構(gòu)。關(guān)于這個(gè)工具包概述的e文原版鏈接地址是http: //gee.cs.oswego.edu/dl/cpjslides/util.pdf。該工具包主要包括三大部分:同步、通道和線程池執(zhí)行器。第一部分 主要是用來定制鎖,資源管理,其他的同步用途;通道則主要是為緩沖和隊(duì)列服務(wù)的;線程池執(zhí)行器則提供了一組完善的復(fù)雜的線程池實(shí)現(xiàn)。
    --主要的結(jié)構(gòu)如下圖所示

    4.2.1 Sync
    acquire/release協(xié)議的主要接口
    - 用來定制鎖,資源管理,其他的同步用途
    - 高層抽象接口
    - 沒有區(qū)分不同的加鎖用法

    實(shí)現(xiàn)
    -Mutex, ReentrantLock, Latch, CountDown,Semaphore, WaiterPreferenceSemaphore, FIFOSemaphore, PrioritySemaphore
    還有,有幾個(gè)簡單的實(shí)現(xiàn),例如ObservableSync, LayeredSync

    舉例:如果我們要在程序中獲得一獨(dú)占鎖,可以用如下簡單方式:
    try {
    lock.acquire();
    try {
    action();
    }
    finally {
    lock.release();
    }
    }catch(Exception e){
    }

    程序中,使用lock對象的acquire()方法獲得一獨(dú)占鎖,然后執(zhí)行您的操作,鎖用完后,使用release()方法釋放之即可。呵呵,簡單吧,想 想看,如果您親自撰寫?yīng)氄兼i,大概會考慮到哪些問題?如果關(guān)鍵的鎖得不到怎末辦?用起來是不是會復(fù)雜很多?而現(xiàn)在,以往的很多細(xì)節(jié)和特殊異常情況在這里都 無需多考慮,您盡可以把精力花在解決您的應(yīng)用問題上去。

    4.2.2 通道(Channel)
    為緩沖,隊(duì)列等服務(wù)的主接口

    具體實(shí)現(xiàn)
    LinkedQueue, BoundedLinkedQueue,BoundedBuffer, BoundedPriorityQueue, SynchronousChannel, Slot

    通道例子
    class Service { // ...
    final Channel msgQ = new LinkedQueue();
    public void serve() throws InterruptedException {
    String status = doService();
    msgQ.put(status);
    }
    public Service() { // start background thread
    Runnable logger = new Runnable() {
    public void run() {
    try {
    for(;;)
    System.out.println(msqQ.take());
    }
    catch(InterruptedException ie) {} }
    };
    new Thread(logger).start();
    }
    }
    在后臺服務(wù)器中,緩沖和隊(duì)列都是最常用到的。試想,如果對所有遠(yuǎn)端的請求不排個(gè)隊(duì)列,讓它們一擁而上的去爭奪cpu、內(nèi)存、資源,那服務(wù)器瞬間不當(dāng)?shù)舨殴帧6谶@里,成熟的隊(duì)列和緩沖實(shí)現(xiàn)已經(jīng)提供,您只需要對其進(jìn)行正確初始化并使用即可,大大縮短了開發(fā)時(shí)間。

    4.2.3執(zhí)行器(Executor)
    Executor是這里最重要、也是我們往往最終寫程序要用到的,下面重點(diǎn)對其進(jìn)行介紹。
    類似線程的類的主接口
    - 線程池
    - 輕量級運(yùn)行框架
    - 可以定制調(diào)度算法

    只需要支持execute(Runnable r)
    - 同Thread.start類似

    實(shí)現(xiàn)
    - PooledExecutor, ThreadedExecutor, QueuedExecutor, FJTaskRunnerGroup

    PooledExecutor(線程池執(zhí)行器)是個(gè)最常用到的類,以它為例:
    可修改得屬性如下:
    - 任務(wù)隊(duì)列的類型
    - 最大線程數(shù)
    - 最小線程數(shù)
    - 預(yù)熱(預(yù)分配)和立即(分配)線程
    - 保持活躍直到工作線程結(jié)束
    -- 以后如果需要可能被一個(gè)新的代替
    - 飽和(Saturation)協(xié)議
    -- 阻塞,丟棄,生產(chǎn)者運(yùn)行,等等

    可不要小看上面這數(shù)條屬性,對這些屬性的設(shè)置完全可以等同于您自己撰寫的線程池的成百上千行代碼。下面以筆者撰寫過得一個(gè)GIS服務(wù)器為例:
    該GIS服務(wù)器是一個(gè)典型的“請求-服務(wù)”類型的服務(wù)器,遵循后端程序設(shè)計(jì)的一般框架。首先對所有的請求按照先來先服務(wù)排入一個(gè)請求隊(duì)列,如果瞬間到達(dá)的 請求超過了請求隊(duì)列的容量,則將溢出的請求轉(zhuǎn)移至一個(gè)臨時(shí)隊(duì)列。如果臨時(shí)隊(duì)列也排滿了,則對以后達(dá)到的請求給予一個(gè)“服務(wù)器忙”的提示后將其簡單拋棄。這 個(gè)就夠忙活一陣的了。
    然后,結(jié)合鏈表結(jié)構(gòu)實(shí)現(xiàn)一個(gè)線程池,給池一個(gè)初始容量。如果該池滿,以x2的策略將池的容量動態(tài)增加一倍,依此類推,直到總線程數(shù)服務(wù)達(dá)到系統(tǒng)能力上限, 之后線程池容量不在增加,所有請求將等待一個(gè)空余的返回線程。每從池中得到一個(gè)線程,該線程就開始最請求進(jìn)行GIS信息的服務(wù),如取坐標(biāo)、取地圖,等等。 服務(wù)完成后,該線程返回線程池繼續(xù)為請求隊(duì)列離地后續(xù)請求服務(wù),周而復(fù)始。當(dāng)時(shí)用矢量鏈表來暫存請求,用wait()、 notify() 和 synchronized等原語結(jié)合矢量鏈表實(shí)現(xiàn)線程池,總共約600行程序,而且在運(yùn)行時(shí)間較長的情況下服務(wù)器不穩(wěn)定,線程池被取用的線程有異常消失的 情況發(fā)生。而使用util.concurrent相關(guān)類之后,僅用了幾十行程序就完成了相同的工作而且服務(wù)器運(yùn)行穩(wěn)定,線程池沒有丟失線程的情況發(fā)生。由 此可見util.concurrent包極大的提高了開發(fā)效率,為項(xiàng)目節(jié)省了大量的時(shí)間。
    使用PooledExecutor例子
    import java.net.*;
    /**
    *

    Title:


    *

    Description: 負(fù)責(zé)初始化線程池以及啟動服務(wù)器


    *

    Copyright: Copyright (c) 2003


    *

    Company:


    * @author not attributable
    * @version 1.0
    */
    public class MainServer {
    //初始化常量
    public static final int MAX_CLIENT=100; //系統(tǒng)最大同時(shí)服務(wù)客戶數(shù)
    //初始化線程池
    public static final PooledExecutor pool =
    new PooledExecutor(new BoundedBuffer(10), MAX_CLIENT); //chanel容量為10,
    //在這里為線程池初始化了一個(gè)
    //長度為10的任務(wù)緩沖隊(duì)列。

    public MainServer() {
    //設(shè)置線程池運(yùn)行參數(shù)
    pool.setMinimumPoolSize(5); //設(shè)置線程池初始容量為5個(gè)線程
    pool.discardOldestWhenBlocked();//對于超出隊(duì)列的請求,使用了拋棄策略。
    pool.createThreads(2); //在線程池啟動的時(shí)候,初始化了具有一定生命周期的2個(gè)“熱”線程
    }

    public static void main(String[] args) {
    MainServer MainServer1 = new MainServer();
    new HTTPListener().start();//啟動服務(wù)器監(jiān)聽和處理線程
    new manageServer().start();//啟動管理線程
    }
    }

    類HTTPListener
    import java.net.*;
    /**
    *

    Title:


    *

    Description: 負(fù)責(zé)監(jiān)聽端口以及將任務(wù)交給線程池處理


    *

    Copyright: Copyright (c) 2003


    *

    Company:


    * @author not attributable
    * @version 1.0
    */

    public class HTTPListener extends Thread{
    public HTTPListener() {
    }
    public void run(){
    try{
    ServerSocket server=null;
    Socket clientconnection=null;
    server = new ServerSocket(8008);//服務(wù)套接字監(jiān)聽某地址端口對
    while(true){//無限循環(huán)
    clientconnection =server.accept();
    System.out.println("Client connected in!");
    //使用線程池啟動服務(wù)
    MainServer.pool.execute(new HTTPRequest(clientconnection));//如果收到一個(gè)請求,則從線程池中取一個(gè)線程進(jìn)行服務(wù),任務(wù)完成后,該線程自動返還線程池
    }
    }catch(Exception e){
    System.err.println("Unable to start serve listen:"+e.getMessage());
    e.printStackTrace();
    }
    }
    }

    關(guān)于util.concurrent工具包就有選擇的介紹到這,更詳細(xì)的信息可以閱讀這些java源代碼的API文檔。Doug Lea是個(gè)很具有“open”精神的作者,他將util.concurrent工具包的java源代碼全部公布出來,有興趣的讀者可以下載這些源代碼并細(xì) 細(xì)品味。 

    5    結(jié)束語
    以上內(nèi)容介紹了線程池基本原理以及設(shè)計(jì)后臺服務(wù)程序應(yīng)考慮到的問題,并結(jié)合實(shí)例詳細(xì)介紹了重要的多線程開發(fā)工具包util.concurrent的構(gòu)架和使用。結(jié)合使用已有完善的開發(fā)包,后端服務(wù)程序的開發(fā)周期將大大縮短,同時(shí)程序性能也有了保障。

    posted @ 2011-03-23 13:25 Sheldon Sun 閱讀(248) | 評論 (0)編輯 收藏

    JAVA事務(wù),JTA,JDBC,JDO,DAO,JNDI概念

    引用http://dyldragon.javaeye.com/blog/789374

    一、什么是Java事務(wù)

    通常的觀念認(rèn)為,事務(wù)僅與數(shù)據(jù)庫相關(guān)。 
    事務(wù)必須服從ISO/IEC所制定的ACID原則。

    ACID是原子性(atomicity)、一致性(consistency)、隔離性(isolation)和持久性(durability)的縮寫。

    事務(wù)的原子性表示事務(wù)執(zhí)行過程中的任何失敗都將導(dǎo)致事務(wù)所做的任何修改失效。

    一致性表示當(dāng)事務(wù)執(zhí)行失敗時(shí),所有被該事務(wù)影響的數(shù)據(jù)都應(yīng)該恢復(fù)到事務(wù)執(zhí)行前的狀態(tài)。

    隔離性表示在事務(wù)執(zhí)行過程中對數(shù)據(jù)的修改,在事務(wù)提交之前對其他事務(wù)不可見。

    持久性表示已提交的數(shù)據(jù)在事務(wù)執(zhí)行失敗時(shí),數(shù)據(jù)的狀態(tài)都應(yīng)該正確。


         
    通俗的理解,事務(wù)是一組原子操作單元,從數(shù)據(jù)庫角度說,就是一組SQL指令,要么全部執(zhí)行成功,若因?yàn)槟硞€(gè)原因其中一條指令執(zhí)行有錯(cuò)誤,則撤銷先前執(zhí)行過的所有指令。更簡答的說就是:要么全部執(zhí)行成功,要么撤銷不執(zhí)行。


    既然事務(wù)的概念從數(shù)據(jù)庫而來,那Java事務(wù)是什么?之間有什么聯(lián)系?  實(shí)際上,一個(gè)Java應(yīng)用系統(tǒng),如果要操作數(shù)據(jù)庫,則通過JDBC來實(shí)現(xiàn)的。增加、修改、刪除都是通過相應(yīng)方法間接來實(shí)現(xiàn)的,事務(wù)的控制也相應(yīng)轉(zhuǎn)移到Java程序代碼中。因此,數(shù)據(jù)庫操作的事務(wù)習(xí)慣上就稱為Java事務(wù)。


    二、為什么需要事務(wù)

    事務(wù)是為解決數(shù)據(jù)安全操作提出的,事務(wù)控制實(shí)際上就是控制數(shù)據(jù)的安全訪問。具一個(gè)簡單例子:比如銀行轉(zhuǎn)帳業(yè)務(wù),賬戶A要將自己賬戶上的1000 元轉(zhuǎn)到B賬戶下面,A賬戶余額首先要減去1000元,然后B賬戶要增加1000元。假如在中間網(wǎng)絡(luò)出現(xiàn)了問題,A賬戶減去1000元已經(jīng)結(jié)束,B因?yàn)榫W(wǎng)絡(luò)中斷而操作失敗,那么整個(gè)業(yè)務(wù)失敗,必須做出控制,要求A賬戶轉(zhuǎn)帳業(yè)務(wù)撤銷。這才能保證業(yè)務(wù)的正確性,完成這個(gè)操走就需要事務(wù),將A賬戶資金減少和B賬戶資金增加方到一個(gè)事務(wù)里面,要么全部執(zhí)行成功,要么操作全部撤銷,這樣就保持了數(shù)據(jù)的安全性。


    三、Java事務(wù)的類型 
        Java 
    事務(wù)的類型有三種:JDBC事務(wù)、JTA(Java Transaction API)事務(wù)、容器事務(wù)。 
    1
    JDBC事務(wù) 
    JDBC 
    事務(wù)是用 Connection 對象控制的。JDBC Connection 接口( java.sql.Connection )提供了兩種事務(wù)模式:自動提交和手工提交。 java.sql.Connection 提供了以下控制事務(wù)的方法:

    public void setAutoCommit(boolean) 
    public boolean getAutoCommit() 
    public void commit() 
    public void rollback() 
    使用 JDBC 事務(wù)界定時(shí),您可以將多個(gè) SQL 語句結(jié)合到一個(gè)事務(wù)中。JDBC 事務(wù)的一個(gè)缺點(diǎn)是事務(wù)的范圍局限于一個(gè)數(shù)據(jù)庫連接。一個(gè) JDBC 事務(wù)不能跨越多個(gè)數(shù)據(jù)庫。 
    2
    JTA(Java Transaction API)事務(wù) 
        JTA 
    是一種高層的,與實(shí)現(xiàn)無關(guān)的,與協(xié)議無關(guān)的API,應(yīng)用程序和應(yīng)用服務(wù)器可以使用JTA來訪問事務(wù)。 
    JTA
    允許應(yīng)用程序執(zhí)行分布式事務(wù)處理--在兩個(gè)或多個(gè)網(wǎng)絡(luò)計(jì)算機(jī)資源上訪問并且更新數(shù)據(jù),這些數(shù)據(jù)可以分布在多個(gè)數(shù)據(jù)庫上。JDBC驅(qū)動程序的JTA支持極大地增強(qiáng)了數(shù)據(jù)訪問能力。 
    如果計(jì)劃用 JTA 界定事務(wù),那么就需要有一個(gè)實(shí)現(xiàn) javax.sql.XADataSource  javax.sql.XAConnection  javax.sql.XAResource接口的 JDBC 驅(qū)動程序。一個(gè)實(shí)現(xiàn)了這些接口的驅(qū)動程序?qū)⒖梢詤⑴c JTA 事務(wù)。一個(gè) XADataSource 對象就是一個(gè)XAConnection 對象的工廠。 XAConnection s 是參與 JTA 事務(wù)的 JDBC 連接。 
    您將需要用應(yīng)用服務(wù)器的管理工具設(shè)置 XADataSource 。從應(yīng)用服務(wù)器和 JDBC 驅(qū)動程序的文檔中可以了解到相關(guān)的指導(dǎo)。 
    J2EE 
    應(yīng)用程序用 JNDI 查詢數(shù)據(jù)源。一旦應(yīng)用程序找到了數(shù)據(jù)源對象,它就調(diào)用 javax.sql.DataSource.getConnection() 以獲得到數(shù)據(jù)庫的連接。 
         XA 
    連接與非 XA 連接不同。一定要記住 XA 連接參與了 JTA 事務(wù)。這意味著 XA 連接不支持 JDBC 的自動提交功能。同時(shí),應(yīng)用程序一定不要對 XA 連接調(diào)用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() 。相反,應(yīng)用程序應(yīng)該使用 UserTransaction.begin() UserTransaction.commit()  serTransaction.rollback() 

    3、容器事務(wù) 
         
    容器事務(wù)主要是J2EE應(yīng)用服務(wù)器提供的,容器事務(wù)大多是基于JTA完成,這是一個(gè)基于JNDI的,相當(dāng)復(fù)雜的API實(shí)現(xiàn)。相對編碼實(shí)現(xiàn)JTA 事務(wù)管理,我們可以通過EJB容器提供的容器事務(wù)管理機(jī)制(CMT)完成同一個(gè)功能,這項(xiàng)功能由J2EE應(yīng)用服務(wù)器提供。這使得我們可以簡單的指定將哪個(gè)方法加入事務(wù),一旦指定,容器將負(fù)責(zé)事務(wù)管理任務(wù)。這是我們土建的解決方式,因?yàn)橥ㄟ^這種方式我們可以將事務(wù)代碼排除在邏輯編碼之外,同時(shí)將所有困難交給 J2EE容器去解決。使用EJB CMT的另外一個(gè)好處就是程序員無需關(guān)心JTA API的編碼,不過,理論上我們必須使用EJB 
    四、三種事務(wù)差異 
    1
    JDBC事務(wù)控制的局限性在一個(gè)數(shù)據(jù)庫連接內(nèi),但是其使用簡單。 
    2
    JTA事務(wù)的功能強(qiáng)大,事務(wù)可以跨越多個(gè)數(shù)據(jù)庫或多個(gè)DAO,使用也比較復(fù)雜。 
    3
    、容器事務(wù),主要指的是J2EE應(yīng)用服務(wù)器提供的事務(wù)管理,局限于EJB應(yīng)用使用。 


    JTA

    Java事務(wù)API(JTA;Java Transaction API)和它的同胞Java事務(wù)服務(wù)(JTS;Java Transaction Service),為J2EE平臺提供了分布式事務(wù)服務(wù)。一個(gè)分布式事務(wù)(distributed transaction)包括一個(gè)事務(wù)管理器(transaction manager)和一個(gè)或多個(gè)資源管理器(resource manager)。一個(gè)資源管理器(resource manager)是任意類型的持久化數(shù)據(jù)存儲。事務(wù)管理器(transaction manager)承擔(dān)著所有事務(wù)參與單元者的相互通訊的責(zé)任。下圖顯示了事務(wù)管理器和資源管理的間的關(guān)系。


    JTA事務(wù)比JDBC事務(wù)更強(qiáng)大。一個(gè)JTA事務(wù)可以有多個(gè)參與者,而一個(gè)JDBC事務(wù)則被限定在一個(gè)單一的數(shù)據(jù)庫連接。下列任一個(gè)Java平臺的組件都可以參與到一個(gè)JTA事務(wù)中:

    JDBC連接

    • JDO PersistenceManager 對象
    • JMS 隊(duì)列
    • JMS 主題
    • 企業(yè)JavaBeans(EJB)
    • 一個(gè)用J2EE Connector Architecture 規(guī)范編譯的資源分配器。


    DAO

    DAO是Data Access Object數(shù)據(jù)訪問接口,數(shù)據(jù)訪問:顧名思義就是與數(shù)據(jù)庫打交道。夾在業(yè)務(wù)邏輯與數(shù)據(jù)庫資源中間。對數(shù)據(jù)庫進(jìn)行CURD(增刪查改操作)。

     

      在核心J2EE模式中是這樣介紹DAO模式的:為了建立一個(gè)健壯的J2EE應(yīng)用,應(yīng)該將所有對數(shù)據(jù)源的訪問操作抽象封裝在一個(gè)公共API中。用程序設(shè)計(jì)的語言來說,就是建立一個(gè)接口,接口中定義了此應(yīng)用程序中將會用到的所有事務(wù)方法。在這個(gè)應(yīng)用程序中,當(dāng)需要和數(shù)據(jù)源進(jìn)行交互的時(shí)候則使用這個(gè)接口,并且編寫一個(gè)單獨(dú)的類來實(shí)現(xiàn)這個(gè)接口在邏輯上對應(yīng)這個(gè)特定的數(shù)據(jù)存儲。


    JDBC

    JDBC(Java Data Base Connectivity,java數(shù)據(jù)庫連接)是一種用于執(zhí)行SQL語句的Java API,可以為多種關(guān)系數(shù)據(jù)庫提供統(tǒng)一訪問,它由一組用Java語言編寫的類和接口組成。JDBC為工具/數(shù)據(jù)庫開發(fā)人員提供了一個(gè)標(biāo)準(zhǔn)的API,據(jù)此可以構(gòu)建更高級的工具和接口,使數(shù)據(jù)庫開發(fā)人員能夠用純 Java API 編寫數(shù)據(jù)庫應(yīng)用程序,同時(shí),JDBC也是個(gè)商標(biāo)名。

     

    有了JDBC,向各種關(guān)系數(shù)據(jù)發(fā)送SQL語句就是一件很容易的事。換言之,有了JDBC API,就不必為訪問Sybase數(shù)據(jù)庫專門寫一個(gè)程序,為訪問Oracle數(shù)據(jù)庫又專門寫一個(gè)程序,或?yàn)樵L問Informix數(shù)據(jù)庫又編寫另一個(gè)程序等等,程序員只需用JDBC API寫一個(gè)程序就夠了,它可向相應(yīng)數(shù)據(jù)庫發(fā)送SQL調(diào)用。同時(shí),將Java語言和JDBC結(jié)合起來使程序員不必為不同的平臺編寫不同的應(yīng)用程序,只須寫一遍程序就可以讓它在任何平臺上運(yùn)行,這也是Java語言“編寫一次,處處運(yùn)行”的優(yōu)勢。


    簡單地說,JDBC 可做三件事:與數(shù)據(jù)庫建立連接、發(fā)送 操作數(shù)據(jù)庫的語句并處理結(jié)果。


    JDO

    JDO(Java Data Object )是一個(gè)JAVA用于存取某種數(shù)據(jù)倉庫中的對象的標(biāo)準(zhǔn)化API。JDO提供了透明的對象存儲,因此對開發(fā)人員來說,存儲數(shù)據(jù)對象完全不需要額外的代碼(如JDBC API的使用)。這些繁瑣的例行工作已經(jīng)轉(zhuǎn)移到JDO產(chǎn)品提供商身上,使開發(fā)人員解脫出來,從而集中時(shí)間和精力在業(yè)務(wù)邏輯上。另外,JDO很靈活,因?yàn)樗梢栽谌魏螖?shù)據(jù)底層上運(yùn)行。JDBC只是面向關(guān)系數(shù)據(jù)庫(RDBMS)JDO更通用,提供到任何數(shù)據(jù)底層的存儲功能,比如關(guān)系數(shù)據(jù)庫、文件、XML以及對象數(shù)據(jù)庫(ODBMS)等等,使得應(yīng)用可移植性更強(qiáng)。


    JNDI

    英文全稱是:Java Naming and Directory Interface

    術(shù)語解釋:一組幫助做多個(gè)命名和目錄服務(wù)接口的API。

    JNDI(Java Naming and Directory Interface)是SUN公司提供的一種標(biāo)準(zhǔn)的Java命名系統(tǒng)接口,JNDI提供統(tǒng)一的客戶端API,通過不同的訪問提供者接口JNDI SPI的實(shí)現(xiàn),由管理者將JNDI API映射為特定的命名服務(wù)和目錄系統(tǒng),使得Java應(yīng)用程序可以和這些命名服務(wù)和目錄服務(wù)之間進(jìn)行交互。集群JNDI實(shí)現(xiàn)了高可靠性JNDI[8],通過服務(wù)器的集群,保證了JNDI的負(fù)載平衡和錯(cuò)誤恢復(fù)。在全局共享的方式下,集群中的一個(gè)應(yīng)用服務(wù)器保證本地JNDI樹的獨(dú)立性,并擁有全局的JNDI樹。每個(gè)應(yīng)用服務(wù)器在把部署的服務(wù)對象綁定到自己本地的JNDI樹的同時(shí),還綁定到一個(gè)共享的全局JNDI樹,實(shí)現(xiàn)全局JNDI和自身JNDI的聯(lián)系。


     

    JNDI(Java Naming and Directory Interface)是一個(gè)應(yīng)用程序設(shè)計(jì)的API,為開發(fā)人員提供了查找和訪問各種

     

    命名和目錄服務(wù)的通用、統(tǒng)一的接口,類似JDBC都是構(gòu)建在抽象層上。

     

    JNDI可訪問的現(xiàn)有的目錄及服務(wù)有:DNS、XNam 、Novell目錄服務(wù)、LDAP(Lightweight Directory Access Protocol 輕型目錄訪問協(xié)議)、 CORBA對象服務(wù)、文件系統(tǒng)、Windows XP/2000/NT/Me/9x的注冊表、RMI、

     


     

    DSML v1&v2、NIS。

     


    JNDI與JDBC

    JNDI提供了一種統(tǒng)一的方式,可以用在網(wǎng)絡(luò)上查找和訪問服務(wù)。通過指定一個(gè)資源名稱,該名稱對應(yīng)于數(shù)據(jù)庫或命名服務(wù)中的一個(gè)記錄,同時(shí)返回?cái)?shù)據(jù)庫連接建立所必須的信息。

    JNDI主要有兩部分組成:應(yīng)用程序編輯接口和服務(wù)供應(yīng)商接口。應(yīng)用程序編程接口提供了Java應(yīng)用程序訪問各種命名和目錄服務(wù)的功能,服務(wù)供應(yīng)商接口提供了任意一種服務(wù)的供應(yīng)商使用的功能。

     

     

    Java代碼  收藏代碼
    1. try{  
    2.   Context cntxt = new InitialContext();  
    3.   DataSource ds = (DataSource) cntxt.lookup("jdbc/dpt");  
    4. }  
    5.   catch(NamingException ne){  
    6.   ...  
    7. }  

    posted @ 2011-03-22 17:35 Sheldon Sun 閱讀(1131) | 評論 (1)編輯 收藏

    Restart

    From now, i will restart my blog , try to record sth of my life, including some thoughts and research results of technology, the only little hope is that the blog can leave my memory of life, as time flying, when i open it , i can get something.

    Technology - Hibernate collection:
    Maybe i used to write sth related before.
    Several points as follows:
    1. Define interface as property, for Hibernate will use its own implementation during runtime.
    2. <key> element is used to identiry foreign key for specified table.
    3. <element> and <composite-element> is used for value type definition while <one-to-many> and <many-to-many> is used for entities type.
    4. indexed-collections contain : map, list, index is used to record position for certain record in the container.<map-key> for map while <index-list> for list.
    Next two items is for bidirection:
    5. inverse can be set in either sides for many-to-many relation.
    6. For one-to-many,  many sides will mantain relationship between object. exception happened when many side is index container.in this situation, it is not a completely "bidirectoinal".

    7. Sort is done in memory while order by is down in DB.
    8. <Bag> is used when property is defined as list, but <index-list> is not welcome.
    9. <idbag> is a list which can generate an id for primary key.

    posted @ 2008-06-11 18:27 Sheldon Sun 閱讀(508) | 評論 (0)編輯 收藏

    Interpret and command pattern

    解釋器模式:
    編譯器用的比較多。
    針對某一特定語法的分析, 解釋, 并進(jìn)行處理!
    E.g: Expression = expression1 | expression2 | repeatableExpresson|Literal
    針對整個(gè)Expression, 分析出其每個(gè)組成的expresion1, expression2, 對每個(gè)分析出的結(jié)果, 都有相應(yīng)的處理類! 并初始化出處理類的實(shí)例進(jìn)行處理!
    Literal代表元數(shù)據(jù) !
    如果對一個(gè)汽車組件的各個(gè)生產(chǎn)廠商進(jìn)行解釋器模式分析的話: 汽車 = 輪胎 + 發(fā)動機(jī) + 框架 那么首先建立一個(gè)分析程序,分析汽車的組成, 并針對每個(gè)部件初始化一個(gè)不見對應(yīng)的對象, 來匹配該部件! 并調(diào)用部件的特有方法, 處理部件, 返回生產(chǎn)廠家的名稱!

    這個(gè)例子好失敗, Interpret 模式優(yōu)點(diǎn)在表達(dá)式的租成有很多模塊, 每個(gè)模塊重復(fù)的包含其他模塊的情況下, 達(dá)到代碼重用的目的! 所以除了正則表達(dá)式, 編譯器以外, 暫時(shí)想不出什么好的例子來!

    命令行模式:
    Struts 應(yīng)用是典型的命令行模式。
    1。 把請求參數(shù)話。
    2。 對每個(gè)請求配置相應(yīng)的處理類。處理類有統(tǒng)一的接口。
    3。 配置請求與處理類的對應(yīng)關(guān)系。
    4。 調(diào)用處理類統(tǒng)一接口。

    沒什么好說的!




    今天比較凡, 感覺自己職業(yè)發(fā)展已經(jīng)到達(dá)了一個(gè)瓶頸, 不知道怎么發(fā)展才好!
    感覺自己交流能力比較差, 大家在一起的時(shí)候都是聽別人說! 自己很少發(fā)言, 做編碼已經(jīng)感覺沒有太大意思了, 因?yàn)楝F(xiàn)在的公司只注重結(jié)果, 不看中代碼的質(zhì)量,開發(fā)出來很容易, 但開發(fā)好的代碼很難! 周圍的同事開發(fā)出來代碼的水平比我都差很多, 也一樣通過, 搞得自己想提高自己都沒有動力!
    想提高一下交流能力, 不知道轉(zhuǎn)行做QA會不會有點(diǎn)改善, 或者還家公司?
    比較迷茫!

    posted @ 2007-11-22 16:56 Sheldon Sun 閱讀(303) | 評論 (0)編輯 收藏

    Chain of responsibility

    剛才看了看職責(zé)鏈模式, 沒什么概念, 腦袋還是比較混亂! 把思路寫出來!

    職責(zé)鏈主要是為了一個(gè)請求, 可能有很多個(gè)處理者, 這些處理者數(shù)目并不固定而設(shè)計(jì)的!

    對每種處理, 都會有一個(gè)處理類來對應(yīng)! 沒個(gè)具體的處理類都會有一個(gè)后繼: succor, 這個(gè)后繼比處理類更廣泛! 如果當(dāng)前的處理類可以處理改請求, 則處理,否則使用后繼的處理方法!

    感覺最關(guān)鍵的一點(diǎn)就是對后繼者的定義, 那為什么不用繼承機(jī)制呢???

    posted @ 2007-11-21 16:49 Sheldon Sun 閱讀(340) | 評論 (1)編輯 收藏

    Validate xml

    package testSchema;

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;

    import org.apache.commons.codec.binary.Base64;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.DocumentHelper;
    import org.dom4j.Element;
    import org.dom4j.Namespace;
    import org.dom4j.io.SAXReader;
    import org.dom4j.tree.DefaultNamespace;

    import org.iso_relax.verifier.Schema;
    import org.iso_relax.verifier.Verifier;
    import org.iso_relax.verifier.VerifierConfigurationException;
    import org.iso_relax.verifier.VerifierFactory;
    import org.iso_relax.verifier.VerifierFilter;
    import org.xml.sax.EntityResolver;
    import org.xml.sax.ErrorHandler;
    import org.xml.sax.InputSource;
    import org.xml.sax.SAXException;
    import org.xml.sax.SAXParseException;

    import com.sun.msv.verifier.jarv.TheFactoryImpl;

    public class ValidateXML {
       
        public Document validate(InputStream stream, String xsdName) throws IOException{
       
        Document result = null;
        InputStream xmlStream = stream;
        InputStream schemaStream = this.getClass().getResourceAsStream(xsdName);
        SAXReader reader;
        try {
            reader = createSAXReader(schemaStream);
            result = reader.read(xmlStream);
            xmlStream.close();
            schemaStream.close();
        } catch (DocumentException e) {
            System.out.println("Validate failed !");
            e.printStackTrace();           
        } catch(IOException e) {
            System.out.println("Xsd file does not exist !");
            e.printStackTrace();           
        }
        catch (Exception e) {
            System.out.println("Xsd file format error !");
            e.printStackTrace();
        }
       
        return result;
    }

    private SAXReader createSAXReader(InputStream xsdStream) throws VerifierConfigurationException, SAXException, IOException {
        VerifierFactory factory = new TheFactoryImpl();
    Schema schema = factory.compileSchema(xsdStream);

    Verifier verifier = schema.newVerifier();
    verifier.setErrorHandler(new ErrorHandler() {
        public void error(SAXParseException e) {
        System.out.println("ERROR: " + e);
        }

        public void fatalError(SAXParseException e) {
        System.out.println("FATAL: " + e);
        }

        public void warning(SAXParseException e) {
        System.out.println("WARNING: " + e);
        }
    });

    // now install the verifying filter
    VerifierFilter filter = verifier.getVerifierFilter();
    SAXReader reader = new SAXReader();
    reader.setXMLFilter(filter);
    return reader;
    }


    public static void main(String[] args) throws IOException {
        ValidateXML validateXML = new ValidateXML();
    //    InputStream schemaStream = validateXML.getClass().getResourceAsStream("Response.xml");
    //    validateXML.validate(schemaStream, "BAK-Response.xsd");
        validateXML.validateByDtd("hibernate-configuration-3.0.dtd", "src\\testSchema\\hibernate.cfg.xml");
    }

    public Document validateByDtd(String dtdFile, String xmlFile) {
        List errors = new ArrayList();
        SAXReader saxReader = new SAXReader();
        saxReader.setEntityResolver(new DTDEntityResolver(dtdFile));
        saxReader.setErrorHandler(new ErrorLogger(xmlFile, errors));
        saxReader.setValidation(true);
        Document doc = null;
        try {
        doc = saxReader.read(xmlFile);
        } catch (DocumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
       
        return doc;
    }

    public static class ErrorLogger implements ErrorHandler {
        private String file;
        private List errors;
        ErrorLogger(String file, List errors) {
            this.file=file;
            this.errors = errors;
        }
        public void error(SAXParseException error) {
            System.err.println( "Error parsing XML: " + file + '(' + error.getLineNumber() + ") " + error.getMessage() );
            errors.add(error);
        }
        public void fatalError(SAXParseException error) {
            System.err.println(error);
        }
        public void warning(SAXParseException warn) {
            System.err.println( "Warning parsing XML: " + file + '(' + warn.getLineNumber() + ") " + warn.getMessage() );
        }
    }


    public static class DTDEntityResolver implements EntityResolver, Serializable {

        private static final Log log = LogFactory.getLog( DTDEntityResolver.class );

       
        private String dtdFile;
        public DTDEntityResolver(String dtdFile) {
            this.dtdFile = dtdFile;
        }
        public InputSource resolveEntity(String publicId, String systemId) {
            if ( systemId != null ) {
                InputStream dtdStream = this.getClass().getResourceAsStream(dtdFile);
                InputSource source = new InputSource( dtdStream );
                source.setPublicId( publicId );
                source.setSystemId( systemId );
                       
                return source;
            }
            // use default behavior
            return null;
        }

    }

    }

    posted @ 2007-08-08 09:53 Sheldon Sun 閱讀(580) | 評論 (0)編輯 收藏

    Hibernate - Component

    1. Component is value type, can not shared between entities, dont own identifier!
    2. Declaration for mapping under component element.
    3. When storing in set(or other collection type), use composite-element.
    4. When using as primary key, use composite-id.
    5. Dynamic component.



    posted @ 2007-06-19 09:31 Sheldon Sun 閱讀(303) | 評論 (0)編輯 收藏

    Hibernate - Persistent class

    1. Hibernate recommand persisten class as a standard javabean naming convention, but not required, Hibernate can access fileds directory too.
    But a no-argument constuctor is requeried for hibernate to instiante an object of the class by refection.

    2. Indentifier property if optional too, but needed if we want to use the full feature set of hibernate, for hibernate will distinguish object by identifiers while some special operation. e.g:  merge(), saveOrUpdate.

    3. Equals() and hasdCode() mehtod is recommanded to implenent when you want to store persisntent class in a Set or manipulate object span sessions.

    4. There are other 2 ways to define enity object except java class, Map and xml, the defect maybe can not do compile check, metrit is more flexisble than java.

    5. Tuplizier!!!!

    Hibernate integrated with J2EE infrastructure:
    Two main point:
    1. Hidden Configuration.config().buildSessionFacotory operation.
    2. Bound session factory to jndi namespace through many way. e.g: MBean
     

    posted @ 2007-06-14 11:12 Sheldon Sun 閱讀(559) | 評論 (0)編輯 收藏

    Inheritance strategy

    There are three kinds of basic strategies for inheritence mapping:
    1. table per hierarchy.
    2. table per subclass.
    3. table per concreteclass.

    Table structure maybe the root reason to determine which kind strategy will be used.

    Table per hierarchy:
    With subclass element.
    A discriminator column will be used to distinguish subclass.
    Limitation: no not null constraint on sub class's property.
    Fault: redandance data will be generated.

    Table per subclass:
    With joined-class elment.
    There are tables for super class and each subclass, for every subclass, key elemnt is used to referenced to super class's primary key, and all common properties will be stored in super table. The relation between super table and sub table is one-to-one.
    Fault: complex table structure.


    Table per concrete class:
    With union-class elemnt.
    Super class responsible for genrate id and all common properties wich will stored in sub table.
    Fault: redandance data will be generated.
    Limitation: all common column should used the same column name for the properties are defined in super class.

    posted @ 2007-06-01 10:55 Sheldon Sun 閱讀(255) | 評論 (0)編輯 收藏

    HbmBinder

    Walks an XML mapping document and produces the Hibernate configuration-time metamodel (the classes in the mapping package)


     

    1. parse "extend" attribute of subclass, unionclass, joinedclass which defined under <hibernate-mapping> element.

    2. parse "meta" data element.

    3. parse other subclass of root element.

    posted @ 2007-05-30 12:57 Sheldon Sun 閱讀(153) | 評論 (0)編輯 收藏

    Hibernate filter

    1. Hibernate filter is used to give a definition condition in xml mapping files.
    2. Ever session want to use it must enable the filter with name first.
    3. filter is defined in xml with elment <filter-def> under <hibernate-mapping>, used <filter> element under <class> element.
    4. give certain sql condition attribute either in <filter-def> or <filter>.
    5. Support value to filter parameters in application.



    The main purpose is to support global filter.

    posted @ 2007-05-24 13:20 Sheldon Sun 閱讀(436) | 評論 (0)編輯 收藏

    Hibernate query

    1. session.createSqlQuery(), in purpose to increase performance, execute sql directly. addScalar() method is used to sepcify type of columns, add entity to return certain entity instance.
    2. session.getNamedQuery(), execute query defined in mapping files with <sql-query> element, the query can be a defined sql sentence or a procedure, property type and entity type can also be specifid by certain elment.
    3. update, detelet, insert sql can be defined in xml mapping files also.


    The finaly purpose of the query is to enchance performance.

    posted @ 2007-05-24 12:51 Sheldon Sun 閱讀(333) | 評論 (0)編輯 收藏

    Hibernate Criteria

    1. Usage org.hibernage.Criteria interface is to compose criterians included in org.hibernate.criteria package.
    2. Criteria interface inherit org.hibernate.criteria.CriterianSpecification, which only defined some mode value, e.g: flushmode, cach mode, maybe not a good implemnt.
    3. Criterian was implemnt by org.hibernate.impl.criteriaImpl and created by org.hibernate.impl.SessionImplementor, translate class name and sesson to criterian.
    4. Typical usage: session.createCriteria(class).add(Restriction.xx()).list;
    5. Restriction is factory of org.hibernate.criteria.Criteriaon implementation.

    Architecture : Define top level interface to compose low lever sub interface, easy to extense and maintain.

    posted @ 2007-05-24 10:55 Sheldon Sun 閱讀(277) | 評論 (0)編輯 收藏

    Hibernate - Environment

    There are 2 kinds of factory : factory level and System level, factory responsible for every factory instance, System for all facotrys, (only 2 system factory property).
    Evironment got properties for /hibernate.properties first, and then from System.getProperties() to ovrride old one!

    Totally, Evironment represents properties.

    posted @ 2007-05-22 13:57 Sheldon Sun 閱讀(111) | 評論 (0)編輯 收藏

    Collection mappings

    1. Use interface type.
    2. Ordered type collection has index sub-element.
    3. Key element indicates the foreign key referred to entity own the collection.
    4. "element" or "composite element" element is used to specify value type contained in collection.
    5. "many-to-many" or "one-to-many" elmeent is used to sepcify referred type contained in collection.
    6. one-to-many need not an intervening table.(foreign key)

    posted @ 2007-05-22 11:12 Sheldon Sun 閱讀(111) | 評論 (0)編輯 收藏

    Persisitent object

    Hard requirenment:
    1. No-argument construct , package visiblity, usde instantiate object by Constructor.newInstance().

    Option requirement:
    1. Pojo.
    2. Implement hashCode and equals for two resons :
        1) Object will be store in a set property.
        2) Instance span to sesssion scope, make a detached object persistent again, will call equals, for java indentify(==) and db indentify(pk) is not available for the condition(object doest not have identify before persistent),

    Note: hashCode generation should not use indentify proeprty  of object.

    posted @ 2007-05-17 08:51 Sheldon Sun 閱讀(240) | 評論 (0)編輯 收藏

    Hibernate configuration

    Hibernate configuration object is the core and starttime class , initiate it and call its config() method to initial sessionFactory.
    Configuration get properties, mapping , etc information through two ways:
    1. Config file: hibernate.propeties, system, hibernate.cfg.xml(optional, name changed Configuration.doConfig(*.cfg.xml)).
    2. Method: Configuration.addSource, addProperties...

    So config files is only a way of configuration to get config info.



    posted @ 2007-05-16 15:00 Sheldon Sun 閱讀(232) | 評論 (0)編輯 收藏

    0516_2

    Configuration: the class instantiate a sessionng factory, it works as follow:
    1. Get properties for Enviroment.java. Environment get properties from hibernate.properties and System, System propertie is prior to hibernate.properties when name is equal.
    2. Configuration.config will read hibernate.cfg.xml to get more properties and mapping files.


    During last two steps, it will some util class in org.hibernate.util to help handle file.

    3. Generate ConnectionProvider by its all properties.


    posted @ 2007-05-16 09:17 Sheldon Sun 閱讀(122) | 評論 (0)編輯 收藏

    0516_1

    1. Update make a detached object persistent.
    2. Config mapping relating in mapping files make query as object oriented.
    3. For many-to-many relation relationship, middle table store link to two tables.
    4. Key element is identify the column of middle table.
    5. Db operation happend at the end of a unit work ---- session flush.
    6. For value type, "element" will replace "many-to-many" in set element(acturally, for all java object, hibernate take it as a value type), value type can not shared by more than one instance.
    7. All bi-directional associations need one side as inverse. bi-direction means both sides of mapping mentain relations of middle table, inverse side is a mirror of the other side, during save or update, the other side will handle.

    posted @ 2007-05-16 08:52 Sheldon Sun 閱讀(166) | 評論 (0)編輯 收藏

    session

    1. batch insert/update session.flush session.clear
    2. statlesssession

    posted @ 2007-05-15 13:34 Sheldon Sun 閱讀(80) | 評論 (0)編輯 收藏

    Mapping for inheritance

    There are three main kinds of mapping for inheritance:
    1. table per class hirachy, for each subclass, use discriminator to distinguish different data, subclass specific property can not be null, only one table.
    2. table per subclass, there is a common table for super class, subclass table reference to super table through primary key, add relationship between tables.
    3. table per concrete class, generate too much redandance data, pk was generated by super class.


    some mix mapping is available.



    posted @ 2007-05-14 13:41 Sheldon Sun 閱讀(133) | 評論 (0)編輯 收藏

    hibernate ref1

    1. Entity name: can be used query.
    2. Way of define mapping: xml, xdoclet, annotation.
    3. Gerated properties: timestamp, version, and property can be generated. Types as follows :
    never: default value.
    always: generated when insert and update.
    insert: only geneated when create data, won't change when updated it later.
    4. Create db schema can be written in xml file.

    posted @ 2007-05-14 10:20 Sheldon Sun 閱讀(112) | 評論 (0)編輯 收藏

    Hibernate reference

    1. lite archetecture: application handle connection and transaction, use niminum hibernate api.
    2. full scream architecture: application will ingore underlying jdbc, jta apis, hibernate hold it.
    3. Persistent object stats: persistence, transient and detached.
    4. Session factory: a cache of compiled configuration files for single db, thread-safed, factory of session and client of connectionProvider, an optional cache of data for process, cluster layer.
    5. Session: represent a conversation between application and db, factory of transaction. wrapped conncetion.
    6. Transatcion: specify automic unit of work.
    7. Context session: hibernateUtil class, for certain application, the scope of current is different, have different context concept. (need more research!)
    8. Configration: store xml to java, can got it through specify xml, java class and proeprties.
    9. Hibernate mapping: mapping java type to SQL type.
    10. Custome mapping type: implement UserType or CompsiteUserType, can define short name, chould get certain value of property by key value.(useless)
    11. Entity and Value: entity can be shared by more than one persistent class as reference.


    posted @ 2007-05-14 09:45 Sheldon Sun 閱讀(247) | 評論 (0)編輯 收藏

    再論Singleton模式

    Singleton模式可能是應(yīng)用最廣泛的模式之一了, 但有些錯(cuò)誤的應(yīng)用。
    ?Singleton的實(shí)現(xiàn): 有兩種方式, 如下:
    1. class Test { public static final Test instance = new Test(); private Test() {} }
    ?2. class Test { private static final Test instance = new Test(); private Test() {} public static Test getInstance() { return instance; } } 這兩種方法都要求構(gòu)造器是私有的, 這樣就可以防止該類外的對象創(chuàng)建新的TEST對象。 但相對而言, 推薦使用第二種方法, 因?yàn)槠涓哂徐`活性,當(dāng)我們改變創(chuàng)建對象的方式的時(shí)候, 不需要改動客戶代碼。 第一種方法較第二種有一點(diǎn)完全可以忽略不計(jì)的效率的提高。
    ?但應(yīng)避免如下代碼實(shí)現(xiàn)Singleton: class Test { private static Test singleton = null; private Test() {} public Test getSingleton() { if(singleton == null) { singleton = new Test(); } return singleton; } } 因?yàn)閲?yán)格上講, 這并不能完全實(shí)現(xiàn)Singleton模式,而且會導(dǎo)致程序出錯(cuò), 這同著名的線程問題--DCL實(shí)效的原理是完全一樣的:
    JVM創(chuàng)建對象的過程可以分為幾個(gè)步驟:創(chuàng)建空間, 把所有的變量賦值位默認(rèn)值, 初始化。。。 當(dāng)有兩個(gè)線程A和B同事進(jìn)入該方法, A先執(zhí)行, A創(chuàng)建Test實(shí)例的空間, 這時(shí),因?yàn)镃PU的指令流機(jī)制,時(shí)間片段正好輪到B線程, 這時(shí)B判斷singleton是否為NULL, 因?yàn)锳已經(jīng)為Test的實(shí)例分配了空間, 所以JVM認(rèn)為實(shí)例已經(jīng)創(chuàng)建了, B繼續(xù)執(zhí)行, 更糟糕的是B調(diào)用了singleton, 這時(shí)因?yàn)樗]有初始化完全, 所以拋出NullPointerException, 太糟糕了!

    posted @ 2006-10-30 14:10 Sheldon Sun 閱讀(188) | 評論 (0)編輯 收藏

    <2006年10月>
    24252627282930
    1234567
    891011121314
    15161718192021
    22232425262728
    2930311234

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(3)

    隨筆檔案

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 18禁成人网站免费观看| 日本免费人成网ww555在线| 永久免费无码日韩视频| 中国性猛交xxxxx免费看| 久久国产精品免费看| 四虎在线最新永久免费| 日本免费人成黄页在线观看视频| 免费大学生国产在线观看p| 亚洲码国产精品高潮在线| 亚洲综合一区二区精品导航| 亚洲免费观看在线视频| 在线观看亚洲网站| 中文字幕在线成人免费看| 永久黄色免费网站| 国产乱子伦片免费观看中字| 亚洲欧洲∨国产一区二区三区| 亚洲日韩中文字幕| 羞羞漫画登录页面免费| 午夜精品免费在线观看| a级毛片无码免费真人| 亚洲性日韩精品国产一区二区| 久久丫精品国产亚洲av| 香蕉视频亚洲一级| 午夜精品免费在线观看| 国产成人免费高清在线观看| 国产亚洲精久久久久久无码| 亚洲中文字幕AV在天堂| 久久精品无码免费不卡| 大地资源二在线观看免费高清| 亚洲色欲久久久久综合网| 亚洲福利电影在线观看| 一级特黄录像视频免费| 波多野结衣在线免费观看| 亚洲区不卡顿区在线观看| 亚洲一级在线观看| 国产一级婬片A视频免费观看| 在线观看AV片永久免费| 亚洲av午夜福利精品一区人妖| 亚洲日本va一区二区三区| 99精品免费视频| 免费看国产一级片|