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

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

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

    隨筆-59  評(píng)論-31  文章-0  trackbacks-0
      2012年1月5日

    Microsoft SQL Server 2008 基本安裝說明

    安裝SQL2008的過程與SQL2005的程序基本一樣,只不過在安裝的過程中部分選項(xiàng)有所改變,當(dāng)然如果只熟悉SQL2000安裝的同志來說則是一個(gè)革命性的變動(dòng),

    一、安裝前的準(zhǔn)備
    1. 需要.Net Framework 3.5,若在Vista或更高的OS上需要3.5 SP1的支持(在SQL2008安裝的前會(huì)自動(dòng)更新安裝)
    2. 需要Widnows PowerShell的支持,WPS是一個(gè)功能非常強(qiáng)大的Shell應(yīng)用,命令與DOX/UNIX兼容并支持直接調(diào)用.NET模塊做行命令編輯,是非常值得深入研究的工具(在SQL2008安裝時(shí)會(huì)自動(dòng)更新安裝)
    3. 需要確保Windows Installer的成功啟動(dòng),需要4.5以上版本(需要檢查服務(wù)啟動(dòng)狀態(tài)service.msc)
    4. 需要MDAC2.8 sp1的支持(XP以上系統(tǒng)中已集成)
    5. 若機(jī)器上已經(jīng)安裝Visual studio 2008則需要VS 2008 sp1以上版本的支持(需要自己從MS的網(wǎng)站上下載安裝http://www.microsoft.com/downloads/details.aspx?familyid=FBEE1648-7106-44A7-9649-6D9F6D58056E&displaylang=en

     

    二、安裝配置過程
    1.進(jìn)行SQL Server安裝中心,選擇"安裝"選項(xiàng),在新的電腦上安裝SQL2008可以直接選擇“全新SQL Server獨(dú)立安裝或向現(xiàn)有安裝功能",將會(huì)安裝一個(gè)默認(rèn)SQL實(shí)列,如下圖

    2.功能選擇,對(duì)于只安裝數(shù)據(jù)庫(kù)服務(wù)器來說,功能的選擇上可以按實(shí)際工作需要來制定,本人一般選擇:數(shù)據(jù)庫(kù)引擎服務(wù)、客戶端工具連接、SQL Server 聯(lián)機(jī)叢書、管理工具-基本、管理工具-完整
         其中數(shù)據(jù)庫(kù)引擎服務(wù)是SQL數(shù)據(jù)庫(kù)的核心服務(wù),Analysis及Reporting服務(wù)可按部署要求安裝,這兩個(gè)服務(wù)可能需要IIS的支持。如下圖


    3.實(shí)列設(shè)置,可直接選擇默認(rèn)實(shí)例進(jìn)行安裝,或則若同一臺(tái)服務(wù)器中有多個(gè)數(shù)據(jù)服務(wù)實(shí)列可按不同實(shí)列名進(jìn)行安裝。如圖


    4.服務(wù)器配置,服務(wù)器配置主要是服務(wù)啟動(dòng)帳戶的配置,服務(wù)的帳戶名推薦使用NT AUTHORITY\SYSTEM的系統(tǒng)帳戶,并指定當(dāng)前選擇服務(wù)的啟動(dòng)類型,如圖

    5.數(shù)據(jù)庫(kù)引擎配置,在當(dāng)前配置中主要設(shè)置SQL登錄驗(yàn)證模式及賬戶密碼,與SQL的數(shù)據(jù)存儲(chǔ)目錄,身份驗(yàn)證模式推薦使用混合模式進(jìn)行驗(yàn)證,在安裝過程中內(nèi)置的SQL Server系統(tǒng)管理員帳戶(sa)的密碼比較特殊,SQL2008對(duì)SA的密碼強(qiáng)度要求相對(duì)比較高,需要有大小寫字母、數(shù)字及符號(hào)組成,否則將不允許你繼續(xù)安裝。在"指定Sql Server管理員"中最好指定本機(jī)的系統(tǒng)管理員administrator。如圖


     

    分類: SQL 雜文
    posted @ 2013-09-27 13:27 RoyPayne 閱讀(240) | 評(píng)論 (0)編輯 收藏
       谷歌瀏覽器的cookie:
           依次點(diǎn)擊設(shè)置--高級(jí)選項(xiàng)--內(nèi)容設(shè)置--cookies--選擇“顯示cookies和其他網(wǎng)站數(shù)據(jù)按鈕就可以看到了

    firefox:
          依次點(diǎn)開FF瀏覽器工具選項(xiàng): 工具》選項(xiàng)》隱私》在歷史選項(xiàng)框中選擇“使用自定義歷史記錄設(shè)置” 進(jìn)入后,再選擇“顯示Cookies”.出來一個(gè)對(duì)話框,里面就是FF記錄的所有Cookie。其值你也可以很方便查看到。




    posted @ 2013-01-28 06:54 RoyPayne 閱讀(2917) | 評(píng)論 (1)編輯 收藏
          死鎖是一個(gè)經(jīng)典的多線程問題,因?yàn)椴煌木€程都在等待那些根本不可能被釋放的鎖,
    從而導(dǎo)致所有的工作都無法完成。假設(shè)有兩個(gè)線程,分別代表兩個(gè)饑餓的人,他們必須共享刀叉并輪流吃飯。
    他們都需要獲得兩個(gè)鎖:共享刀和共享叉的鎖。假如線程 "A" 獲得了刀,而線程 "B" 獲得了叉。
    線程 A 就會(huì)進(jìn)入阻塞狀態(tài)來等待獲得叉,而線程 B 則阻塞來等待 A 所擁有的刀。
          
          讓所有的線程按照同樣的順序獲得一組鎖。這種方法消除了 X 和 Y 的擁有者分別等待對(duì)方的資源的問題。
      將多個(gè)鎖組成一組并放到同一個(gè)鎖下。前面死鎖的例子中,可以創(chuàng)建一個(gè)銀器對(duì)象的鎖。于是在獲得刀或叉之前都必須獲得這個(gè)銀器的鎖。
      將那些不會(huì)阻塞的可獲得資源用變量標(biāo)志出來。當(dāng)某個(gè)線程獲得銀器對(duì)象的鎖時(shí),就可以通過檢查變量來判斷是否整個(gè)銀器集合中的對(duì)象鎖都可獲得。如果是,它就可以獲得相關(guān)的鎖,否則,就要釋放掉銀器這個(gè)鎖并稍后再嘗試。
      最重要的是,在編寫代碼前認(rèn)真仔細(xì)地設(shè)計(jì)整個(gè)系統(tǒng)。多線程是困難的,在開始編程之前詳細(xì)設(shè)計(jì)系統(tǒng)能夠幫助你避免難以發(fā)現(xiàn)死鎖的問題。
    posted @ 2012-12-10 10:54 RoyPayne 閱讀(344) | 評(píng)論 (0)編輯 收藏
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
     
    <head>
      
    <title> New Document </title>
      
    <meta name="Generator" content="EditPlus">
      
    <meta name="Author" content="">
      
    <meta name="Keywords" content="">
      
    <meta name="Description" content="">
     
    </head>
        
    <script type="text/javascript" src="jquery.js"></script>
        
    <script type="text/javascript">

            
    function go() {
                
    var str="";
                $(
    "input[name='checkbox']:checkbox").each(function(){ 
                    
    if($(this).attr("checked")){
                        str 
    += $(this).val()+","
                    }
                })
                
    //alert(str);
                str.split(",");
                alert(str[
    0]);
            }
        
    </script>
     
    <body>
      
    <div>
        
    <input type="text" id="content" value="111"/>
        
    <input type="checkbox" name="checkbox" value="1"/>
        
    <input type="checkbox" name="checkbox" value="2"/>
        
    <input type="checkbox" name="checkbox" value="3"/>
        
    <input type="checkbox" name="checkbox" value="4"/>
        
    <input type="checkbox" name="checkbox" value="5"/>
        
    <input type="button" id="test" onclick="go();"/>
      
    </div>
     
    </body>
    </html>
    posted @ 2012-03-02 09:40 RoyPayne 閱讀(88798) | 評(píng)論 (21)編輯 收藏
    XFire WebService開發(fā)快速起步


    http://lavasoft.blog.51cto.com/62575/105956/
    posted @ 2012-02-01 14:50 RoyPayne 閱讀(355) | 評(píng)論 (0)編輯 收藏
         摘要: oracle腳本:drop table t_student cascade constraints;Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->/*==================================================...  閱讀全文
    posted @ 2012-01-31 13:25 RoyPayne 閱讀(2249) | 評(píng)論 (2)編輯 收藏

    在Session的緩存中存放的是相互關(guān)聯(lián)的對(duì)象圖。默認(rèn)情況下,當(dāng)Hibernate從數(shù)據(jù)庫(kù)中加載Customer對(duì)象時(shí),會(huì)同時(shí)加載所有關(guān)聯(lián)的 Order對(duì)象。以Customer和Order類為例,假定ORDERS表的CUSTOMER_ID外鍵允許為null

    以下Session的find()方法用于到數(shù)據(jù)庫(kù)中檢索所有的Customer對(duì)象: 

    List customerLists=session.find("from Customer as c"); 

    運(yùn)行以上find()方法時(shí),Hibernate將先查詢CUSTOMERS表中所有的記錄,然后根據(jù)每條記錄的ID,到ORDERS表中查詢有參照關(guān)系的記錄,Hibernate將依次執(zhí)行以下select語(yǔ)句: 

    select * from CUSTOMERS; 
    select * from ORDERS where CUSTOMER_ID=1; 
    select * from ORDERS where CUSTOMER_ID=2; 
    select * from ORDERS where CUSTOMER_ID=3; 
    select * from ORDERS where CUSTOMER_ID=4; 

    通過以上5條select語(yǔ)句,Hibernate最后加載了4個(gè)Customer對(duì)象和5個(gè)Order對(duì)象,在內(nèi)存中形成了一幅關(guān)聯(lián)的對(duì)象圖.


    Hibernate在檢索與Customer關(guān)聯(lián)的Order對(duì)象時(shí),使用了默認(rèn)的立即檢索策略。這種檢索策略存在兩大不足: 

    (1) select語(yǔ)句的數(shù)目太多,需要頻繁的訪問數(shù)據(jù)庫(kù),會(huì)影響檢索性能。如果需要查詢n個(gè)Customer對(duì)象,那么必須執(zhí)行n+1次select查詢語(yǔ) 句。這就是經(jīng)典的n+1次select查詢問題。這種檢索策略沒有利用SQL的連接查詢功能,例如以上5條select語(yǔ)句完全可以通過以下1條 select語(yǔ)句來完成: 

    select * from CUSTOMERS left outer join ORDERS 
    on CUSTOMERS.ID=ORDERS.CUSTOMER_ID 

    以上select語(yǔ)句使用了SQL的左外連接查詢功能,能夠在一條select語(yǔ)句中查詢出CUSTOMERS表的所有記錄,以及匹配的ORDERS表的記錄。 

    (2)在應(yīng)用邏輯只需要訪問Customer對(duì)象,而不需要訪問Order對(duì)象的場(chǎng)合,加載Order對(duì)象完全是多余的操作,這些多余的Order對(duì)象白白浪費(fèi)了許多內(nèi)存空間。 
    為了解決以上問題,Hibernate提供了其他兩種檢索策略:延遲檢索策略和迫切左外連接檢索策略。延遲檢索策略能避免多余加載應(yīng)用程序不需要訪問的關(guān)聯(lián)對(duì)象,迫切左外連接檢索策略則充分利用了SQL的外連接查詢功能,能夠減少select語(yǔ)句的數(shù)目。


    對(duì)數(shù)據(jù)庫(kù)訪問還是必須考慮性能問題的, 在設(shè)定了1 對(duì)多這種關(guān)系之后, 查詢就會(huì)出現(xiàn)傳說中的n +1 問題。 
    1 )1 對(duì)多,在1 方,查找得到了n 個(gè)對(duì)象, 那么又需要將n 個(gè)對(duì)象關(guān)聯(lián)的集合取出,于是本來的一條sql查詢變成了n +1 條 
    2)多對(duì)1 ,在多方,查詢得到了m個(gè)對(duì)象,那么也會(huì)將m個(gè)對(duì)象對(duì)應(yīng)的1 方的對(duì)象取出, 也變成了m+1

    怎么解決n +1 問題? 
    1 )lazy=true, hibernate3開始已經(jīng)默認(rèn)是lazy=true了;lazy=true時(shí)不會(huì)立刻查詢關(guān)聯(lián)對(duì)象,只有當(dāng)需要關(guān)聯(lián)對(duì)象(訪問其屬性,非id字段)時(shí)才會(huì)發(fā)生查詢動(dòng)作。 

    2)二級(jí)緩存, 在對(duì)象更新,刪除,添加相對(duì)于查詢要少得多時(shí), 二級(jí)緩存的應(yīng)用將不怕n +1 問題,因?yàn)榧词沟谝淮尾樵兒苈笾苯泳彺婷幸彩呛芸斓摹?nbsp;
    不同解決方法,不同的思路,第二條卻剛好又利用了n +1 。

    3) 當(dāng)然你也可以設(shè)定fetch=join(annotation : @ManyToOne() @Fetch(FetchMode.JOIN))

    posted @ 2012-01-30 14:20 RoyPayne 閱讀(10907) | 評(píng)論 (1)編輯 收藏
    1. 在web.xml文件中加入Filter聲明 
    <!-- Spring security Filter -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    這個(gè)Filter會(huì)攔截所有的URL請(qǐng)求,并且對(duì)這些URL請(qǐng)求進(jìn)行Spring Security的驗(yàn)證。 

    注意,springSecurityFilterChain這個(gè)名稱是由命名空間默認(rèn)創(chuàng)建的用于處理web安全的一個(gè)內(nèi)部的bean的id。所以你在你的Spring配置文件中,不應(yīng)該再使用這個(gè)id作為你的bean。 

    與Acegi的配置不同,Acegi需要自行聲明一個(gè)Spring的bean來作為Filter的實(shí)現(xiàn),而使用Spring Security后,無需再額外定義bean,而是使用<http>元素進(jìn)行配置。 

    通過擴(kuò)展Spring Security的默認(rèn)實(shí)現(xiàn)來進(jìn)行用戶和權(quán)限的管理 

    事實(shí)上,Spring Security提供了2個(gè)認(rèn)證的接口,分別用于模擬用戶和權(quán)限,以及讀取用戶和權(quán)限的操作方法。這兩個(gè)接口分別是:UserDetails和UserDetailsService。 

    public interface UserDetails extends Serializable {
        
        GrantedAuthority[] getAuthorities();

        String getPassword();

        String getUsername();

        boolean isAccountNonExpired();

        boolean isAccountNonLocked();

        boolean isCredentialsNonExpired();

        boolean isEnabled();
    }

    public interface UserDetailsService {
        UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException, DataAccessException;
    }

    非常清楚,一個(gè)接口用于模擬用戶,另外一個(gè)用于模擬讀取用戶的過程。所以我們可以通過實(shí)現(xiàn)這兩個(gè)接口,來完成使用數(shù)據(jù)庫(kù)對(duì)用戶和權(quán)限進(jìn)行管理的需求。在這里,我將給出一個(gè)使用Hibernate來定義用戶和權(quán)限之間關(guān)系的示例。 
    posted @ 2012-01-20 10:41 RoyPayne 閱讀(1717) | 評(píng)論 (1)編輯 收藏
         摘要: Quartz是一個(gè)強(qiáng)大的企業(yè)級(jí)任務(wù)調(diào)度框架,Spring中繼承并簡(jiǎn)化了Quartz,下面就看看在Spring中怎樣配置Quartz:  閱讀全文
    posted @ 2012-01-19 14:53 RoyPayne 閱讀(316) | 評(píng)論 (0)編輯 收藏
    1.自定義攔截器繼承AbstractInterceptor,重寫public String intercept(ActionInvocation invocation)方法。
    intercept方法有ActionInvocation對(duì)象,可以獲取當(dāng)前的Action請(qǐng)求。
    public class AuthorityInterceptor extends AbstractInterceptor {
        private static final long serialVersionUID = 1L; 
        private Logger LOG = Logger.getLogger(AuthorityInterceptor.class.getName()); 
        
        private AuthorityUtil authorityUtil;
        
        public String intercept(ActionInvocation invocation) throws Exception {
            if (authorityUtil == null) {
                authorityUtil = new AuthorityUtil();
            }
            
            //獲取當(dāng)前用戶所有的權(quán)限
            List<OperatorPurviewDO> operatorPurviews = getCurrentOperatorPurviews();
            
            //獲取當(dāng)前操作的url
            String currentUrl = getCurrentUrl(); 
            
             //如果是超級(jí)管理員或有當(dāng)前url的權(quán)限,那么直接返回。
            if (OperatorUtil.getIsSuperAdmin() ||(OperatorUtil.getLoginName()!=null&&authorityUtil.checkUrl(operatorPurviews, currentUrl))){
                 return invocation.invoke();
            }
             
            if (!OperatorUtil.getIsSuperAdmin()&&operatorPurviews.size()==0) {
                LOG.info("此用戶:" + OperatorUtil.getLoginName() + " 沒有任何角色,沒有權(quán)限執(zhí)行任何功能"); 
                return "loginErr"; 
            }   
                return "authorityErr";
        }

    2.struts2.xml 配置interceptor

      2.1 定義自定義攔截器
    <interceptor name="authorityInterceptor" class="com.wasu.eis.authority.AuthorityInterceptor" /> 
      2.2 加上struts2默認(rèn)攔截器,形成攔截器棧
                <interceptor-stack name="eisManagerBasicStack">
                    <interceptor-ref name="exception"/>
                    <interceptor-ref name="alias"/>
                    <interceptor-ref name="servletConfig"/>
                    <interceptor-ref name="prepare"/>
                    <interceptor-ref name="i18n"/>
                    <interceptor-ref name="chain"/>
                    <interceptor-ref name="debugging"/>
                    <interceptor-ref name="profiling"/>
                    <interceptor-ref name="scopedModelDriven"/>
                    <interceptor-ref name="modelDriven"/>
                    <interceptor-ref name="checkbox"/>
                    <interceptor-ref name="staticParams"/>
                    <interceptor-ref name ="fileUploadStack" /> 
                    <interceptor-ref name="params">
                      <param name="excludeParams">dojo\..*</param>
                    </interceptor-ref>
                    <interceptor-ref name="conversionError"/>
                    <interceptor-ref name="validation">
                        <param name="excludeMethods">input,back,cancel,browse</param>
                    </interceptor-ref>
                    <interceptor-ref name="workflow">
                        <param name="excludeMethods">input,back,cancel,browse</param>
                    </interceptor-ref>
                </interceptor-stack>
                
                <interceptor-stack name="authorityInterceptorStack">
                    <interceptor-ref name="authorityInterceptor" />
                    <interceptor-ref name="eisManagerBasicStack" />
                </interceptor-stack>

    3.設(shè)置為缺省的攔截器

    <default-interceptor-ref name="authorityInterceptorStack"/>
    posted @ 2012-01-17 16:35 RoyPayne 閱讀(2756) | 評(píng)論 (0)編輯 收藏
         摘要: 分頁(yè)顯示一直是web開發(fā)中一大煩瑣的難題,傳統(tǒng)的網(wǎng)頁(yè)設(shè)計(jì)只在一個(gè)JSP或者ASP頁(yè)面中書寫所有關(guān)于數(shù)據(jù)庫(kù)操作的代碼,那樣做分頁(yè)可能簡(jiǎn)單一點(diǎn),但當(dāng)把網(wǎng)站分層開發(fā)后,分頁(yè)就比較困難了,下面是我做Spring+Hibernate+Struts2項(xiàng)目時(shí)設(shè)計(jì)的分頁(yè)代碼,與大家分享交流。  閱讀全文
    posted @ 2012-01-17 13:56 RoyPayne 閱讀(656) | 評(píng)論 (1)編輯 收藏

    1.第一個(gè)例子:

    <s:select list="{'aa','bb','cc'}" theme="simple" headerKey="00" headerValue="00"></s:select>

    2.第二個(gè)例子:

    <s:select list="#{1:'aa',2:'bb',3:'cc'}"  label="abc" listKey="key" listValue="value"  headerKey="0" headerValue="aabb">

    3.第三個(gè)例子:

    <%
    java.util.HashMap map = new java.util.LinkedHashMap();
    map.put(1,"aaa");
    map.put(2,"bbb");
    map.put(3,"ccc");
    request.setAttribute("map",map);
    request.setAttribute("aa","2");
    %>
    <s:select list="#request.map"  label="abc" listKey="key" listValue="value"
     value="#request.aa"  headerKey="0" headerValue="aabb"></
    s:select
    >
    headerKey headerValue 為設(shè)置缺省值

    4.第四個(gè)例子

    public class Program implements Serializable {
        /**    serialVersionUID */
        private static final long serialVersionUID = 1L;
        private int programid;
        private String programName;
        public int getProgramid() {
            return programid;
        }
        public void setProgramid(int programid) {
            this.programid = programid;
        }
            public String getProgramName() {
            return programName;
        }
        public void setProgramName(String programName) {
            this.programName = programName;
        }
    }

    在 xxx extends  extends ActionSupport {
        private  List<Program> programs ;
           public List<Program> getPrograms() {
            return programs;
        }
        public void setPrograms(List<Program> programs) {
                this.programs = programs;
        }
    }


    在jsp頁(yè)面
          <s:select list="programs "  listValue="programName " listKey="programid "  name="program" id="program"
                 headerKey="0l" headerValue="    "   value="bean.programid "
                 ></s:select>  
    紅色部分為在action里面的list,黃色為<option value="xxx">value</option>對(duì)應(yīng)bean里面的字段programName 
    綠色為<option value="xxx",對(duì)應(yīng)bean里面的字段programid

    紫色為設(shè)定select被選中的值,s:select 會(huì)自動(dòng)在 bean選中 key對(duì)應(yīng)的值

    posted @ 2012-01-12 15:10 RoyPayne 閱讀(248) | 評(píng)論 (0)編輯 收藏
    工作中碰到個(gè)ConcurrentModificationException。代碼如下:
    List list = ...;
    for(Iterator iter = list.iterator(); iter.hasNext();) {
        Object obj = iter.next();
        ...
        if(***) {
            list.remove(obj);
        }
    }
    在執(zhí)行了remove方法之后,再去執(zhí)行循環(huán),iter.next()的時(shí)候,報(bào)java.util.ConcurrentModificationException(當(dāng)然,如果remove的是最后一條,就不會(huì)再去執(zhí)行next()操作了)

    下面來看一下源碼
    public interface Iterator<E> {
        boolean hasNext();
        E next();
        void remove();
    }

    public interface Collection<E> extends Iterable<E> {
        ...
        Iterator<E> iterator();
        boolean add(E o);
        boolean remove(Object o);
        ...
    }

    這里有兩個(gè)remove方法

    接下來來看看AbstractList
    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {  
    //AbstractCollection和List都繼承了Collection
        protected transient int modCount = 0;
        private class Itr implements Iterator<E> {  //內(nèi)部類Itr
            int cursor = 0;
            int lastRet = -1;
            int expectedModCount = modCount;

            public boolean hasNext() {
                return cursor != size();
            }

            public E next() {
                checkForComodification();  //特別注意這個(gè)方法
                try {
                    E next = get(cursor);
                    lastRet = cursor++;
                    return next;
                } catch(IndexOutOfBoundsException e) {
                    checkForComodification();
                    throw new NoSuchElementException();
                }
            }

            public void remove() {
                if (lastRet == -1)
                    throw new IllegalStateException();
                checkForComodification();

                try {
                    AbstractList.this.remove(lastRet);  //執(zhí)行remove對(duì)象的操作
                    if (lastRet < cursor)
                        cursor--;
                    lastRet = -1;
                    expectedModCount = modCount;  //重新設(shè)置了expectedModCount的值,避免了ConcurrentModificationException的產(chǎn)生
                } catch(IndexOutOfBoundsException e) {
                    throw new ConcurrentModificationException();
                }
            }

            final void checkForComodification() {
                if (modCount != expectedModCount)  //當(dāng)expectedModCount和modCount不相等時(shí),就拋出ConcurrentModificationException
                    throw new ConcurrentModificationException();
            }
        }    
    }


    remove(Object o)在ArrayList中實(shí)現(xiàn)如下:
    public boolean remove(Object o) {
        if (o == null) {
                for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    private void fastRemove(int index) {
        modCount++;  //只增加了modCount
        ....
    }

    所以,產(chǎn)生ConcurrentModificationException的原因就是:
    執(zhí)行remove(Object o)方法之后,modCount和expectedModCount不相等了。然后當(dāng)代碼執(zhí)行到next()方法時(shí),判斷了checkForComodification(),發(fā)現(xiàn)兩個(gè)數(shù)值不等,就拋出了該Exception。
    要避免這個(gè)Exception,就應(yīng)該使用remove()方法。

    這里我們就不看add(Object o)方法了,也是同樣的原因,但沒有對(duì)應(yīng)的add()方法。一般嘛,就另建一個(gè)List了


    下面是網(wǎng)上的其他解釋,更能從本質(zhì)上解釋原因:
    Iterator 是工作在一個(gè)獨(dú)立的線程中,并且擁有一個(gè) mutex 鎖。 Iterator 被創(chuàng)建之后會(huì)建立一個(gè)指向原來對(duì)象的單鏈索引表,當(dāng)原來的對(duì)象數(shù)量發(fā)生變化時(shí),這個(gè)索引表的內(nèi)容不會(huì)同步改變,所以當(dāng)索引指針往后移動(dòng)的時(shí)候就找不到要迭代的對(duì)象,所以按照 fail-fast 原則 Iterator 會(huì)馬上拋出 java.util.ConcurrentModificationException 異常。
    所以 Iterator 在工作的時(shí)候是不允許被迭代的對(duì)象被改變的。但你可以使用 Iterator 本身的方法 remove() 來刪除對(duì)象, Iterator.remove() 方法會(huì)在刪除當(dāng)前迭代對(duì)象的同時(shí)維護(hù)索引的一致性。
    posted @ 2012-01-06 17:14 RoyPayne 閱讀(206) | 評(píng)論 (0)編輯 收藏
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
     
    /**
        本例介紹一個(gè)特殊的隊(duì)列:BlockingQueue,如果BlockQueue是空的,從BlockingQueue取東西的操作將會(huì)被阻斷進(jìn)入等待狀態(tài),直到BlockingQueue進(jìn)了東西才會(huì)被喚醒.同樣,如果BlockingQueue是滿的,任何試圖往里存東西的操作也會(huì)被阻斷進(jìn)入等待狀態(tài),直到BlockingQueue里有空間才會(huì)被喚醒繼續(xù)操作.
        本例再次實(shí)現(xiàn)11.4線程----條件Condition中介紹的籃子程序,不過這個(gè)籃子中最多能放的蘋果數(shù)不是1,可以隨意指定.當(dāng)籃子滿時(shí),生產(chǎn)者進(jìn)入等待狀態(tài),當(dāng)籃子空時(shí),消費(fèi)者等待.
     
    */
    /**
        使用BlockingQueue的關(guān)鍵技術(shù)點(diǎn)如下:
        1.BlockingQueue定義的常用方法如下:
            1)add(anObject):把a(bǔ)nObject加到BlockingQueue里,即如果BlockingQueue可以容納,則返回true,否則招聘異常
            2)offer(anObject):表示如果可能的話,將anObject加到BlockingQueue里,即如果BlockingQueue可以容納,則返回true,否則返回false.
            3)put(anObject):把a(bǔ)nObject加到BlockingQueue里,如果BlockQueue沒有空間,則調(diào)用此方法的線程被阻斷直到BlockingQueue里面有空間再繼續(xù).
            4)poll(time):取走BlockingQueue里排在首位的對(duì)象,若不能立即取出,則可以等time參數(shù)規(guī)定的時(shí)間,取不到時(shí)返回null
            5)take():取走BlockingQueue里排在首位的對(duì)象,若BlockingQueue為空,阻斷進(jìn)入等待狀態(tài)直到Blocking有新的對(duì)象被加入為止
        2.BlockingQueue有四個(gè)具體的實(shí)現(xiàn)類,根據(jù)不同需求,選擇不同的實(shí)現(xiàn)類
            1)ArrayBlockingQueue:規(guī)定大小的BlockingQueue,其構(gòu)造函數(shù)必須帶一個(gè)int參數(shù)來指明其大小.其所含的對(duì)象是以FIFO(先入先出)順序排序的.
            2)LinkedBlockingQueue:大小不定的BlockingQueue,若其構(gòu)造函數(shù)帶一個(gè)規(guī)定大小的參數(shù),生成的BlockingQueue有大小限制,若不帶大小參數(shù),所生成的BlockingQueue的大小由Integer.MAX_VALUE來決定.其所含的對(duì)象是以FIFO(先入先出)順序排序的
            3)PriorityBlockingQueue:類似于LinkedBlockQueue,但其所含對(duì)象的排序不是FIFO,而是依據(jù)對(duì)象的自然排序順序或者是構(gòu)造函數(shù)的Comparator決定的順序.
            4)SynchronousQueue:特殊的BlockingQueue,對(duì)其的操作必須是放和取交替完成的.
        3.LinkedBlockingQueue和ArrayBlockingQueue比較起來,它們背后所用的數(shù)據(jù)結(jié)構(gòu)不一樣,導(dǎo)致LinkedBlockingQueue的數(shù)據(jù)吞吐量要大于ArrayBlockingQueue,但在線程數(shù)量很大時(shí)其性能的可預(yù)見性低于ArrayBlockingQueue.         
     
    */
    public class BlockingQueueTest {
           /**定義裝蘋果的籃子*/
           public static class Basket{
                  //籃子,能夠容納3個(gè)蘋果
                  BlockingQueue<String> basket = new ArrayBlockingQueue<String>(3);
                  //生產(chǎn)蘋果,放入籃子
                  public void produce() throws InterruptedException{
                         //put方法放入一個(gè)蘋果,若basket滿了,等到basket有位置
                         basket.put("An apple");
                  }
                  //消費(fèi)蘋果,從籃子中取走
                  public String consume() throws InterruptedException{
                         //take方法取出一個(gè)蘋果,若basket為空,等到basket有蘋果為止
                         return basket.take();
                  }
           }
           //測(cè)試方法
           public static void testBasket(){
                  final Basket basket = new Basket();//建立一個(gè)裝蘋果的籃子
                  
    //定義蘋果生產(chǎn)者
                  class Producer implements Runnable{
                         public void run(){
                                try{
                                       while(true){
                                              //生產(chǎn)蘋果
                                              System.out.println("生產(chǎn)者準(zhǔn)備生產(chǎn)蘋果: " + System.currentTimeMillis());
                                              basket.produce();
                                              System.out.println("生產(chǎn)者生產(chǎn)蘋果完畢: " + System.currentTimeMillis());
                                              //休眠300ms
                                              Thread.sleep(300);
                                       }
                                }catch(InterruptedException ex){
                                }
                         }
                  }
                  //定義蘋果消費(fèi)者
                  class Consumer implements Runnable{
                         public void run(){
                                try{
                                       while(true){
                                              //消費(fèi)蘋果
                                              System.out.println("消費(fèi)者準(zhǔn)備消費(fèi)蘋果: " + System.currentTimeMillis());
                                              basket.consume();
                                              System.out.println("消費(fèi)者消費(fèi)蘋果完畢: " + System.currentTimeMillis());
                                              //休眠1000ms
                                              Thread.sleep(1000);
                                       }
                                }catch(InterruptedException ex){
                                }
                         }
                  }
                  ExecutorService service = Executors.newCachedThreadPool();
                  Producer producer = new Producer();
                  Consumer consumer = new Consumer();
                  service.submit(producer);
                  service.submit(consumer);
                  //程序運(yùn)行5s后,所有任務(wù)停止
                  try{
                         Thread.sleep(5000);
                  }catch(InterruptedException ex){
                  }
                  service.shutdownNow();
           }
           public static void main(String[] args){
                  BlockingQueueTest.testBasket();
           }
    }
    posted @ 2012-01-06 16:32 RoyPayne 閱讀(233) | 評(píng)論 (0)編輯 收藏
       Java? 語(yǔ)言包含兩種內(nèi)在的同步機(jī)制:同步塊(或方法)和 volatile 變量。這兩種機(jī)制的提出都是為了實(shí)現(xiàn)代碼線程的安全性。其中 Volatile 變量的同步性較差(但有時(shí)它更簡(jiǎn)單并且開銷更低),而且其使用也更容易出錯(cuò)。在這期的 Java 理論與實(shí)踐中,Brian Goetz 將介紹幾種正確使用 volatile 變量的模式,并針對(duì)其適用性限制提出一些建議。
      Java 語(yǔ)言中的 volatile 變量可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變量所需的編碼較少,并且運(yùn)行時(shí)開銷也較少,但是它所能實(shí)現(xiàn)的功能也僅是 synchronized 的一部分。本文介紹了幾種有效使用 volatile 變量的模式,并強(qiáng)調(diào)了幾種不適合使用 volatile 變量的情形。
      鎖提供了兩種主要特性:互斥(mutual exclusion)可見性(visibility)。互斥即一次只允許一個(gè)線程持有某個(gè)特定的鎖,因此可使用該特性實(shí)現(xiàn)對(duì)共享數(shù)據(jù)的協(xié)調(diào)訪問協(xié)議,這樣,一次就只有一個(gè)線程能夠使用該共享數(shù)據(jù)。可見性要更加復(fù)雜一些,它必須確保釋放鎖之前對(duì)共享數(shù)據(jù)做出的更改對(duì)于隨后獲得該鎖的另一個(gè)線程是可見的 —— 如果沒有同步機(jī)制提供的這種可見性保證,線程看到的共享變量可能是修改前的值或不一致的值,這將引發(fā)許多嚴(yán)重問題。

    Volatile 變量

      Volatile 變量具有 synchronized 的可見性特性,但是不具備原子特性。這就是說線程能夠自動(dòng)發(fā)現(xiàn) volatile 變量的最新值。Volatile 變量可用于提供線程安全,但是只能應(yīng)用于非常有限的一組用例:多個(gè)變量之間或者某個(gè)變量的當(dāng)前值與修改后值之間沒有約束。因此,單獨(dú)使用 volatile 還不足以實(shí)現(xiàn)計(jì)數(shù)器、互斥鎖或任何具有與多個(gè)變量相關(guān)的不變式(Invariants)的類(例如 “start <=end”)。
      出于簡(jiǎn)易性或可伸縮性的考慮,您可能傾向于使用 volatile 變量而不是鎖。當(dāng)使用 volatile 變量而非鎖時(shí),某些習(xí)慣用法(idiom)更加易于編碼和閱讀。此外,volatile 變量不會(huì)像鎖那樣造成線程阻塞,因此也很少造成可伸縮性問題。在某些情況下,如果讀操作遠(yuǎn)遠(yuǎn)大于寫操作,volatile 變量還可以提供優(yōu)于鎖的性能優(yōu)勢(shì)。

    正確使用 volatile 變量的條件

      您只能在有限的一些情形下使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時(shí)滿足下面兩個(gè)條件:
      ● 對(duì)變量的寫操作不依賴于當(dāng)前值。
      ● 該變量沒有包含在具有其他變量的不變式中。
      實(shí)際上,這些條件表明,可以被寫入 volatile 變量的這些有效值獨(dú)立于任何程序的狀態(tài),包括變量的當(dāng)前狀態(tài)。
      第一個(gè)條件的限制使 volatile 變量不能用作線程安全計(jì)數(shù)器。雖然增量操作(x++)看上去類似一個(gè)單獨(dú)操作,實(shí)際上它是一個(gè)由讀取-修改-寫入操作序列組成的組合操作,必須以原子方式執(zhí)行,而 volatile 不能提供必須的原子特性。實(shí)現(xiàn)正確的操作需要使 x 的值在操作期間保持不變,而 volatile 變量無法實(shí)現(xiàn)這點(diǎn)。(然而,如果將值調(diào)整為只從單個(gè)線程寫入,那么可以忽略第一個(gè)條件。)
      大多數(shù)編程情形都會(huì)與這兩個(gè)條件的其中之一沖突,使得 volatile 變量不能像 synchronized 那樣普遍適用于實(shí)現(xiàn)線程安全。清單 1 顯示了一個(gè)非線程安全的數(shù)值范圍類。它包含了一個(gè)不變式 —— 下界總是小于或等于上界。
           
           
    清單 1. 非線程安全的數(shù)值范圍類
    @NotThreadSafe 
    public class NumberRange { 
    private int lower, upper; 
    public int getLower() { return lower; } 
    public int getUpper() { return upper; } 
    public void setLower(int value) { 
    if (value > upper) 
    throw new IllegalArgumentException(); 
    lower = value; 

    public void setUpper(int value) { 
    if (value < lower) 
    throw new IllegalArgumentException(); 
    upper = value; 

    }

    這種方式限制了范圍的狀態(tài)變量,因此將 lower 和 upper 字段定義為 volatile 類型不能夠充分實(shí)現(xiàn)類的線程安全;從而仍然需要使用同步。否則,如果湊巧兩個(gè)線程在同一時(shí)間使用不一致的值執(zhí)行 setLower 和 setUpper 的話,則會(huì)使范圍處于不一致的狀態(tài)。例如,如果初始狀態(tài)是 (0, 5),同一時(shí)間內(nèi),線程 A 調(diào)用 setLower(4) 并且線程 B 調(diào)用 setUpper(3),顯然這兩個(gè)操作交叉存入的值是不符合條件的,那么兩個(gè)線程都會(huì)通過用于保護(hù)不變式的檢查,使得最后的范圍值是 (4, 3) —— 一個(gè)無效值。至于針對(duì)范圍的其他操作,我們需要使 setLower() 和 setUpper() 操作原子化 —— 而將字段定義為 volatile 類型是無法實(shí)現(xiàn)這一目的的。

    性能考慮

      使用 volatile 變量的主要原因是其簡(jiǎn)易性:在某些情形下,使用 volatile 變量要比使用相應(yīng)的鎖簡(jiǎn)單得多。使用 volatile 變量次要原因是其性能:某些情況下,volatile 變量同步機(jī)制的性能要優(yōu)于鎖。
      很難做出準(zhǔn)確、全面的評(píng)價(jià),例如 “X 總是比 Y 快”,尤其是對(duì) JVM 內(nèi)在的操作而言。(例如,某些情況下 VM 也許能夠完全刪除鎖機(jī)制,這使得我們難以抽象地比較 volatile和 synchronized 的開銷。)就是說,在目前大多數(shù)的處理器架構(gòu)上,volatile 讀操作開銷非常低 —— 幾乎和非 volatile 讀操作一樣。而 volatile 寫操作的開銷要比非 volatile 寫操作多很多,因?yàn)橐WC可見性需要實(shí)現(xiàn)內(nèi)存界定(Memory Fence),即便如此,volatile 的總開銷仍然要比鎖獲取低。
      volatile 操作不會(huì)像鎖一樣造成阻塞,因此,在能夠安全使用 volatile 的情況下,volatile 可以提供一些優(yōu)于鎖的可伸縮特性。如果讀操作的次數(shù)要遠(yuǎn)遠(yuǎn)超過寫操作,與鎖相比,volatile 變量通常能夠減少同步的性能開銷。

    正確使用 volatile 的模式

      很多并發(fā)性專家事實(shí)上往往引導(dǎo)用戶遠(yuǎn)離 volatile 變量,因?yàn)槭褂盟鼈円仁褂面i更加容易出錯(cuò)。然而,如果謹(jǐn)慎地遵循一些良好定義的模式,就能夠在很多場(chǎng)合內(nèi)安全地使用 volatile 變量。要始終牢記使用 volatile 的限制 —— 只有在狀態(tài)真正獨(dú)立于程序內(nèi)其他內(nèi)容時(shí)才能使用 volatile —— 這條規(guī)則能夠避免將這些模式擴(kuò)展到不安全的用例。
      模式 #1:狀態(tài)標(biāo)志 也許實(shí)現(xiàn) volatile 變量的規(guī)范使用僅僅是使用一個(gè)布爾狀態(tài)標(biāo)志,用于指示發(fā)生了一個(gè)重要的一次性事件,例如完成初始化或請(qǐng)求停機(jī)。
      很多應(yīng)用程序包含了一種控制結(jié)構(gòu),形式為 “在還沒有準(zhǔn)備好停止程序時(shí)再執(zhí)行一些工作”,如清單 2 所示:
      清單 2. 將 volatile 變量作為狀態(tài)標(biāo)志使用

    volatile boolean shutdownRequested; 
     
    public void shutdown() { shutdownRequested = true; } 
    public void doWork() { 
    while (!shutdownRequested) { 
    // do stuff 

    }
    很可能會(huì)從循環(huán)外部調(diào)用 shutdown() 方法 —— 即在另一個(gè)線程中 —— 因此,需要執(zhí)行某種同步來確保正確實(shí)現(xiàn) shutdownRequested 變量的可見性。(可能會(huì)從 JMX 偵聽程序、GUI 事件線程中的操作偵聽程序、通過 RMI 、通過一個(gè) Web 服務(wù)等調(diào)用)。然而,使用 synchronized 塊編寫循環(huán)要比使用清單 2 所示的 volatile 狀態(tài)標(biāo)志編寫麻煩很多。由于 volatile 簡(jiǎn)化了編碼,并且狀態(tài)標(biāo)志并不依賴于程序內(nèi)任何其他狀態(tài),因此此處非常適合使用 volatile。
      這種類型的狀態(tài)標(biāo)記的一個(gè)公共特性是:通常只有一種狀態(tài)轉(zhuǎn)換;shutdownRequested 標(biāo)志從 false 轉(zhuǎn)換為 true,然后程序停止。這種模式可以擴(kuò)展到來回轉(zhuǎn)換的狀態(tài)標(biāo)志,但是只有在轉(zhuǎn)換周期不被察覺的情況下才能擴(kuò)展(從 false 到 true,再轉(zhuǎn)換到 false)。此外,還需要某些原子狀態(tài)轉(zhuǎn)換機(jī)制,例如原子變量。
      模式 #2:一次性安全發(fā)布(one-time safe publication)
      缺乏同步會(huì)導(dǎo)致無法實(shí)現(xiàn)可見性,這使得確定何時(shí)寫入對(duì)象引用而不是原語(yǔ)值變得更加困難。在缺乏同步的情況下,可能會(huì)遇到某個(gè)對(duì)象引用的更新值(由另一個(gè)線程寫入)和該對(duì)象狀態(tài)的舊值同時(shí)存在。(這就是造成著名的雙重檢查鎖定(double-checked-locking)問題的根源,其中對(duì)象引用在沒有同步的情況下進(jìn)行讀操作,產(chǎn)生的問題是您可能會(huì)看到一個(gè)更新的引用,但是仍然會(huì)通過該引用看到不完全構(gòu)造的對(duì)象)。
      實(shí)現(xiàn)安全發(fā)布對(duì)象的一種技術(shù)就是將對(duì)象引用定義為 volatile 類型。清單 3 展示了一個(gè)示例,其中后臺(tái)線程在啟動(dòng)階段從數(shù)據(jù)庫(kù)加載一些數(shù)據(jù)。其他代碼在能夠利用這些數(shù)據(jù)時(shí),在使用之前將檢查這些數(shù)據(jù)是否曾經(jīng)發(fā)布過。
      清單 3. 將 volatile 變量用于一次性安全發(fā)布

    public class BackgroundFloobleLoader { 
    public volatile Flooble theFlooble; 
    public void initInBackground() { 
    // do lots of stuff 
    theFlooble = new Flooble(); // this is the only write to theFlooble 


    public class SomeOtherClass { 
    public void doWork() { 
    while (true) { 
    // do some stuff 
    // use the Flooble, but only if it is ready 
    if (floobleLoader.theFlooble != null
    doSomething(floobleLoader.theFlooble); 


    }

    如果 theFlooble 引用不是 volatile 類型,doWork() 中的代碼在解除對(duì) theFlooble 的引用時(shí),將會(huì)得到一個(gè)不完全構(gòu)造的 Flooble。
      該模式的一個(gè)必要條件是:被發(fā)布的對(duì)象必須是線程安全的,或者是有效的不可變對(duì)象(有效不可變意味著對(duì)象的狀態(tài)在發(fā)布之后永遠(yuǎn)不會(huì)被修改)。volatile 類型的引用可以確保對(duì)象的發(fā)布形式的可見性,但是如果對(duì)象的狀態(tài)在發(fā)布后將發(fā)生更改,那么就需要額外的同步。
      模式 #3:獨(dú)立觀察(independent observation)
      安全使用 volatile 的另一種簡(jiǎn)單模式是:定期 “發(fā)布” 觀察結(jié)果供程序內(nèi)部使用。例如,假設(shè)有一種環(huán)境傳感器能夠感覺環(huán)境溫度。一個(gè)后臺(tái)線程可能會(huì)每隔幾秒讀取一次該傳感器,并更新包含當(dāng)前文檔的 volatile 變量。然后,其他線程可以讀取這個(gè)變量,從而隨時(shí)能夠看到最新的溫度值。
      使用該模式的另一種應(yīng)用程序就是收集程序的統(tǒng)計(jì)信息。清單 4 展示了身份驗(yàn)證機(jī)制如何記憶最近一次登錄的用戶的名字。將反復(fù)使用 lastUser 引用來發(fā)布值,以供程序的其他部分使用。
      清單 4. 將 volatile 變量用于多個(gè)獨(dú)立觀察結(jié)果的發(fā)布
    public class UserManager { 
    public volatile String lastUser; 
    public boolean authenticate(String user, String password) { 
    boolean valid = passwordIsValid(user, password); 
    if (valid) { 
    User u = new User(); 
    activeUsers.add(u); 
    lastUser = user; 

    return valid; 

    }

    該模式是前面模式的擴(kuò)展;將某個(gè)值發(fā)布以在程序內(nèi)的其他地方使用,但是與一次性事件的發(fā)布不同,這是一系列獨(dú)立事件。這個(gè)模式要求被發(fā)布的值是有效不可變的 —— 即值的狀態(tài)在發(fā)布后不會(huì)更改。使用該值的代碼需要清楚該值可能隨時(shí)發(fā)生變化。
      模式 #4:“volatile bean” 模式
      volatile bean 模式適用于將 JavaBeans 作為“榮譽(yù)結(jié)構(gòu)”使用的框架。在 volatile bean 模式中,JavaBean 被用作一組具有 getter 和/或 setter 方法 的獨(dú)立屬性的容器。volatile bean 模式的基本原理是:很多框架為易變數(shù)據(jù)的持有者(例如 HttpSession)提供了容器,但是放入這些容器中的對(duì)象必須是線程安全的。
      在 volatile bean 模式中,JavaBean 的所有數(shù)據(jù)成員都是 volatile 類型的,并且 getter 和 setter 方法必須非常普通 —— 除了獲取或設(shè)置相應(yīng)的屬性外,不能包含任何邏輯。此外,對(duì)于對(duì)象引用的數(shù)據(jù)成員,引用的對(duì)象必須是有效不可變的。(這將禁止具有數(shù)組值的屬性,因?yàn)楫?dāng)數(shù)組引用被聲明為 volatile 時(shí),只有引用而不是數(shù)組本身具有 volatile 語(yǔ)義)。對(duì)于任何 volatile 變量,不變式或約束都不能包含 JavaBean 屬性。清單 5 中的示例展示了遵守 volatile bean 模式的 JavaBean:
      清單 5. 遵守 volatile bean 模式的 Person 對(duì)象

    @ThreadSafe 
    public class Person { 
    private volatile String firstName; 
    private volatile String lastName; 
    private volatile int age; 
    public String getFirstName() { return firstName; } 
    public String getLastName() { return lastName; } 
    public int getAge() { return age; } 
    public void setFirstName(String firstName) { 
    this.firstName = firstName; 

    public void setLastName(String lastName) { 
    this.lastName = lastName; 

    public void setAge(int age) { 
    this.age = age; 

    }

    volatile 的高級(jí)模式
      前面幾節(jié)介紹的模式涵蓋了大部分的基本用例,在這些模式中使用 volatile 非常有用并且簡(jiǎn)單。這一節(jié)將介紹一種更加高級(jí)的模式,在該模式中,volatile 將提供性能或可伸縮性優(yōu)勢(shì)。
      volatile 應(yīng)用的的高級(jí)模式非常脆弱。因此,必須對(duì)假設(shè)的條件仔細(xì)證明,并且這些模式被嚴(yán)格地封裝了起來,因?yàn)榧词狗浅P〉母囊矔?huì)損壞您的代碼!同樣,使用更高級(jí)的 volatile 用例的原因是它能夠提升性能,確保在開始應(yīng)用高級(jí)模式之前,真正確定需要實(shí)現(xiàn)這種性能獲益。需要對(duì)這些模式進(jìn)行權(quán)衡,放棄可讀性或可維護(hù)性來?yè)Q取可能的性能收益 —— 如果您不需要提升性能(或者不能夠通過一個(gè)嚴(yán)格的測(cè)試程序證明您需要它),那么這很可能是一次糟糕的交易,因?yàn)槟芸赡軙?huì)得不償失,換來的東西要比放棄的東西價(jià)值更低。
      模式 #5:開銷較低的讀-寫鎖策略
      目前為止,您應(yīng)該了解了 volatile 的功能還不足以實(shí)現(xiàn)計(jì)數(shù)器。因?yàn)?++x 實(shí)際上是三種操作(讀、添加、存儲(chǔ))的簡(jiǎn)單組合,如果多個(gè)線程湊巧試圖同時(shí)對(duì) volatile 計(jì)數(shù)器執(zhí)行增量操作,那么它的更新值有可能會(huì)丟失。
      然而,如果讀操作遠(yuǎn)遠(yuǎn)超過寫操作,您可以結(jié)合使用內(nèi)部鎖和 volatile 變量來減少公共代碼路徑的開銷。清單 6 中顯示的線程安全的計(jì)數(shù)器使用 synchronized 確保增量操作是原子的,并使用 volatile 保證當(dāng)前結(jié)果的可見性。如果更新不頻繁的話,該方法可實(shí)現(xiàn)更好的性能,因?yàn)樽x路徑的開銷僅僅涉及 volatile 讀操作,這通常要優(yōu)于一個(gè)無競(jìng)爭(zhēng)的鎖獲取的開銷。
      清單 6. 結(jié)合使用 volatile 和 synchronized 實(shí)現(xiàn) “開銷較低的讀-寫鎖”
    @ThreadSafe 
    public class CheesyCounter { 
    // Employs the cheap read-write lock trick 
    // All mutative operations MUST be done with the 'this' lock held 
    @GuardedBy("this") private volatileint value; 
    public int getValue() { return value; } 
    public synchronizedint increment() { 
    return value++; 

    }

    之所以將這種技術(shù)稱之為 “開銷較低的讀-寫鎖” 是因?yàn)槟褂昧瞬煌耐綑C(jī)制進(jìn)行讀寫操作。因?yàn)楸纠械膶懖僮鬟`反了使用 volatile 的第一個(gè)條件,因此不能使用 volatile 安全地實(shí)現(xiàn)計(jì)數(shù)器 —— 您必須使用鎖。然而,您可以在讀操作中使用 volatile 確保當(dāng)前值的可見性,因此可以使用鎖進(jìn)行所有變化的操作,使用 volatile 進(jìn)行只讀操作。其中,鎖一次只允許一個(gè)線程訪問值,volatile 允許多個(gè)線程執(zhí)行讀操作,因此當(dāng)使用 volatile 保證讀代碼路徑時(shí),要比使用鎖執(zhí)行全部代碼路徑獲得更高的共享度 —— 就像讀-寫操作一樣。然而,要隨時(shí)牢記這種模式的弱點(diǎn):如果超越了該模式的最基本應(yīng)用,結(jié)合這兩個(gè)競(jìng)爭(zhēng)的同步機(jī)制將變得非常困難。
      結(jié)束語(yǔ)
      與鎖相比,Volatile 變量是一種非常簡(jiǎn)單但同時(shí)又非常脆弱的同步機(jī)制,它在某些情況下將提供優(yōu)于鎖的性能和伸縮性。如果嚴(yán)格遵循 volatile 的使用條件 —— 即變量真正獨(dú)立于其他變量和自己以前的值 —— 在某些情況下可以使用 volatile 代替 synchronized 來簡(jiǎn)化代碼。然而,使用 volatile 的代碼往往比使用鎖的代碼更加容易出錯(cuò)。本文介紹的模式涵蓋了可以使用 volatile 代替 synchronized 的最常見的一些用例。遵循這些模式(注意使用時(shí)不要超過各自的限制)可以幫助您安全地實(shí)現(xiàn)大多數(shù)用例,使用 volatile 變量獲得更佳性能。


    posted @ 2012-01-06 10:44 RoyPayne 閱讀(300) | 評(píng)論 (1)編輯 收藏
         摘要: JSP內(nèi)置對(duì)象:我們?cè)谑褂肑SP進(jìn)行頁(yè)面編程時(shí)可以直接使用而不需自己創(chuàng)建的一些Web容器已為用戶創(chuàng)建好的JSP內(nèi)置對(duì)象。如request,session,response,out等。下面就JSP2.0給出的9個(gè)內(nèi)置對(duì)象: 內(nèi)置對(duì)象類型作用域requestjavax.servlet.http.HttpServletRequestrequestresponsejavax.servlet.ht...  閱讀全文
    posted @ 2012-01-05 16:36 RoyPayne 閱讀(18587) | 評(píng)論 (1)編輯 收藏
    一、Propagation (事務(wù)的傳播屬性)

    Propagation :  key屬性確定代理應(yīng)該給哪個(gè)方法增加事務(wù)行為。這樣的屬性最重要的部份是傳播行為。有以下選項(xiàng)可供使用:PROPAGATION_REQUIRED--支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù)。這是最常見的選擇。
    PROPAGATION_SUPPORTS--支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
    PROPAGATION_MANDATORY--支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
    PROPAGATION_REQUIRES_NEW--新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
    PROPAGATION_NOT_SUPPORTED--以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
    PROPAGATION_NEVER--以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。

    1: PROPAGATION_REQUIRED
    加入當(dāng)前正要執(zhí)行的事務(wù)不在另外一個(gè)事務(wù)里,那么就起一個(gè)新的事務(wù)
    比如說,ServiceB.methodB的事務(wù)級(jí)別定義為PROPAGATION_REQUIRED, 那么由于執(zhí)行ServiceA.methodA的時(shí)候,
    ServiceA.methodA已經(jīng)起了事務(wù),這時(shí)調(diào)用ServiceB.methodB,ServiceB.methodB看到自己已經(jīng)運(yùn)行在ServiceA.methodA
    的事務(wù)內(nèi)部,就不再起新的事務(wù)。而假如ServiceA.methodA運(yùn)行的時(shí)候發(fā)現(xiàn)自己沒有在事務(wù)中,他就會(huì)為自己分配一個(gè)事務(wù)。
    這樣,在ServiceA.methodA或者在ServiceB.methodB內(nèi)的任何地方出現(xiàn)異常,事務(wù)都會(huì)被回滾。即使ServiceB.methodB的事務(wù)已經(jīng)被
    提交,但是ServiceA.methodA在接下來fail要回滾,ServiceB.methodB也要回滾

    2: PROPAGATION_SUPPORTS
    如果當(dāng)前在事務(wù)中,即以事務(wù)的形式運(yùn)行,如果當(dāng)前不再一個(gè)事務(wù)中,那么就以非事務(wù)的形式運(yùn)行


    3: PROPAGATION_MANDATORY
    必須在一個(gè)事務(wù)中運(yùn)行。也就是說,他只能被一個(gè)父事務(wù)調(diào)用。否則,他就要拋出異常

    4: PROPAGATION_REQUIRES_NEW
    這個(gè)就比較繞口了。 比如我們?cè)O(shè)計(jì)ServiceA.methodA的事務(wù)級(jí)別為PROPAGATION_REQUIRED,ServiceB.methodB的事務(wù)級(jí)別為PROPAGATION_REQUIRES_NEW,
    那么當(dāng)執(zhí)行到ServiceB.methodB的時(shí)候,ServiceA.methodA所在的事務(wù)就會(huì)掛起,ServiceB.methodB會(huì)起一個(gè)新的事務(wù),等待ServiceB.methodB的事務(wù)完成以后,
    他才繼續(xù)執(zhí)行。他與PROPAGATION_REQUIRED 的事務(wù)區(qū)別在于事務(wù)的回滾程度了。因?yàn)镾erviceB.methodB是新起一個(gè)事務(wù),那么就是存在
    兩個(gè)不同的事務(wù)。如果ServiceB.methodB已經(jīng)提交,那么ServiceA.methodA失敗回滾,ServiceB.methodB是不會(huì)回滾的。如果ServiceB.methodB失敗回滾,
    如果他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務(wù)仍然可能提交。

    5: PROPAGATION_NOT_SUPPORTED
    當(dāng)前不支持事務(wù)。比如ServiceA.methodA的事務(wù)級(jí)別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務(wù)級(jí)別是PROPAGATION_NOT_SUPPORTED ,
    那么當(dāng)執(zhí)行到ServiceB.methodB時(shí),ServiceA.methodA的事務(wù)掛起,而他以非事務(wù)的狀態(tài)運(yùn)行完,再繼續(xù)ServiceA.methodA的事務(wù)。

    6: PROPAGATION_NEVER
    不能在事務(wù)中運(yùn)行。假設(shè)ServiceA.methodA的事務(wù)級(jí)別是PROPAGATION_REQUIRED, 而ServiceB.methodB的事務(wù)級(jí)別是PROPAGATION_NEVER ,
    那么ServiceB.methodB就要拋出異常了。

    7: PROPAGATION_NESTED
    理解Nested的關(guān)鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區(qū)別是,PROPAGATION_REQUIRES_NEW另起一個(gè)事務(wù),將會(huì)與他的父事務(wù)相互獨(dú)立,
    而Nested的事務(wù)和他的父事務(wù)是相依的,他的提交是要等和他的父事務(wù)一塊提交的。也就是說,如果父事務(wù)最后回滾,他也要回滾的。
    而Nested事務(wù)的好處是他有一個(gè)savepoint。
    *****************************************
    ServiceA {

    /**
    * 事務(wù)屬性配置為 PROPAGATION_REQUIRED
    */
    void methodA() {
    try {
    //savepoint
    ServiceB.methodB(); //PROPAGATION_NESTED 級(jí)別
    } catch (SomeException) {
    // 執(zhí)行其他業(yè)務(wù), 如 ServiceC.methodC();
    }
    }

    }
    ********************************************
    也就是說ServiceB.methodB失敗回滾,那么ServiceA.methodA也會(huì)回滾到savepoint點(diǎn)上,ServiceA.methodA可以選擇另外一個(gè)分支,比如
    ServiceC.methodC,繼續(xù)執(zhí)行,來嘗試完成自己的事務(wù)。
    但是這個(gè)事務(wù)并沒有在EJB標(biāo)準(zhǔn)中定義。

    Spring事務(wù)的隔離級(jí)別
     1. ISOLATION_DEFAULT: 這是一個(gè)PlatfromTransactionManager默認(rèn)的隔離級(jí)別,使用數(shù)據(jù)庫(kù)默認(rèn)的事務(wù)隔離級(jí)別.
          另外四個(gè)與JDBC的隔離級(jí)別相對(duì)應(yīng)
     2. ISOLATION_READ_UNCOMMITTED: 這是事務(wù)最低的隔離級(jí)別,它充許令外一個(gè)事務(wù)可以看到這個(gè)事務(wù)未提交的數(shù)據(jù)。
          這種隔離級(jí)別會(huì)產(chǎn)生臟讀,不可重復(fù)讀和幻像讀。
     3. ISOLATION_READ_COMMITTED: 保證一個(gè)事務(wù)修改的數(shù)據(jù)提交后才能被另外一個(gè)事務(wù)讀取。另外一個(gè)事務(wù)不能讀取該事務(wù)未提交的數(shù)據(jù)
     4. ISOLATION_REPEATABLE_READ: 這種事務(wù)隔離級(jí)別可以防止臟讀,不可重復(fù)讀。但是可能出現(xiàn)幻像讀。
          它除了保證一個(gè)事務(wù)不能讀取另一個(gè)事務(wù)未提交的數(shù)據(jù)外,還保證了避免下面的情況產(chǎn)生(不可重復(fù)讀)。
     5. ISOLATION_SERIALIZABLE 這是花費(fèi)最高代價(jià)但是最可靠的事務(wù)隔離級(jí)別。事務(wù)被處理為順序執(zhí)行。
          除了防止臟讀,不可重復(fù)讀外,還避免了幻像讀。

    什么是臟數(shù)據(jù),臟讀,不可重復(fù)讀,幻覺讀?
     臟讀: 指當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù),并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫(kù)中,這時(shí),
         另外一個(gè)事務(wù)也訪問這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。因?yàn)檫@個(gè)數(shù)據(jù)是還沒有提交的數(shù)據(jù), 那么另外一
         個(gè)事務(wù)讀到的這個(gè)數(shù)據(jù)是臟數(shù)據(jù),依據(jù)臟數(shù)據(jù)所做的操作可能是不正確的。
        
     不可重復(fù)讀: 指在一個(gè)事務(wù)內(nèi),多次讀同一數(shù)據(jù)。在這個(gè)事務(wù)還沒有結(jié)束時(shí),另外一個(gè)事務(wù)也訪問該同一數(shù)據(jù)。
                 那么,在第一個(gè)事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改,那么第一個(gè)事務(wù)兩次讀到的數(shù)據(jù)
                 可能是不一樣的。這樣就發(fā)生了在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的,因此稱為是不可重復(fù)讀。
                
     幻覺讀: 指當(dāng)事務(wù)不是獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象,例如第一個(gè)事務(wù)對(duì)一個(gè)表中的數(shù)據(jù)進(jìn)行了修改,這種修改涉及
             到表中的全部數(shù)據(jù)行。同時(shí),第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù),這種修改是向表中插入一行新數(shù)據(jù)。那么,
             以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還有沒有修改的數(shù)據(jù)行,就好象發(fā)生了幻覺一樣。
    posted @ 2012-01-05 15:25 RoyPayne 閱讀(391) | 評(píng)論 (0)編輯 收藏
    兩者的區(qū)別有:
    1、最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法。 2、這兩個(gè)方法來自不同的類分別是Thread和Object

    3、wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在
    任何地方使用
    synchronized(x){
    x.notify()
    //或者wait()
    }
    4、sleep必須捕獲異常,而wait,notify和notifyAll不需要捕獲異常
    posted @ 2012-01-05 14:32 RoyPayne 閱讀(462) | 評(píng)論 (0)編輯 收藏

    public class CeilAndFloor {
        public static void main(String[] args) {
        /*
            這兩個(gè)寶貝函數(shù)的主要任務(wù)是截掉小數(shù)以后的位數(shù).
            區(qū)別是: floor總是把數(shù)字變得越來越小,而ceil總是把數(shù)字變大。
                    其實(shí)名字可以理解floor是地板,ceil是天花板。
        
    */

            System.out.println("==============Math.floor()==============");
            System.out.println("Math.floor(99.1) = " + Math.floor(99.1));
            System.out.println("Math.floor(-99.1) = " + Math.floor(-99.1));
            System.out.println("Math.floor(99.9) = " + Math.floor(99.9));
            System.out.println("Math.floor(99.9) = " + Math.floor(-99.9));
            
            System.out.println("\n\n==============Math.ceil()==============");
            System.out.println("Math.ceil(99.1) = " + Math.ceil(99.1));
            System.out.println("Math.ceil(-99.1) = " + Math.ceil(-99.1));
            System.out.println("Math.ceil(99.9) = " + Math.ceil(99.9));
            System.out.println("Math.ceil(99.9) = " + Math.ceil(-99.9));
            
        }
    }
    結(jié)果
    ==============Math.floor()==============
    Math.floor(99.1) = 99.0
    Math.floor(-99.1) = -100.0
    Math.floor(99.9) = 99.0
    Math.floor(99.9) = -100.0

    ==============Math.ceil()==============
    Math.ceil(99.1) = 100.0
    Math.ceil(-99.1) = -99.0
    Math.ceil(99.9) = 100.0
    Math.ceil(99.9) = -99.0
    posted @ 2012-01-05 09:20 RoyPayne 閱讀(364) | 評(píng)論 (0)編輯 收藏
    主站蜘蛛池模板: 国产成人精品日本亚洲专区61| 亚洲国产精华液2020| 免费高清国产视频| 亚洲精品第一国产综合境外资源 | 久青草视频在线观看免费| 免费永久国产在线视频| 亚洲人成欧美中文字幕| 国产日本一线在线观看免费| 久久亚洲精品无码AV红樱桃| 亚洲免费人成在线视频观看| 精品久久香蕉国产线看观看亚洲| av午夜福利一片免费看久久| 国产精品亚洲美女久久久 | 人人揉揉香蕉大免费不卡| 在线亚洲精品自拍| 一级一级毛片免费播放| 免费一级毛片女人图片| 国产成人亚洲综合在线| 国产做床爱无遮挡免费视频| 国产成人亚洲精品91专区高清| 国产成人aaa在线视频免费观看| 亚洲精品无码专区久久| 热99re久久免费视精品频软件| 亚洲人成无码网站在线观看| 插B内射18免费视频| 亚洲午夜福利在线视频| 成在人线AV无码免费| 亚洲av无码专区在线观看亚| 国产在线观看www鲁啊鲁免费| 日韩色视频一区二区三区亚洲| 四虎国产精品免费久久影院| 精品视频免费在线| 亚洲国产精品尤物YW在线观看| 日韩在线一区二区三区免费视频 | 亚洲精品天天影视综合网| 91香蕉国产线在线观看免费| 亚洲成人免费电影| 日韩吃奶摸下AA片免费观看| 亚洲欧洲精品成人久久曰| 国产大片免费观看中文字幕| 人人公开免费超级碰碰碰视频|