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

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

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

    隨筆-59  評論-31  文章-0  trackbacks-0
      2012年1月6日

    Microsoft SQL Server 2008 基本安裝說明

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

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

     

    二、安裝配置過程
    1.進行SQL Server安裝中心,選擇"安裝"選項,在新的電腦上安裝SQL2008可以直接選擇“全新SQL Server獨立安裝或向現有安裝功能",將會安裝一個默認SQL實列,如下圖

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


    3.實列設置,可直接選擇默認實例進行安裝,或則若同一臺服務器中有多個數據服務實列可按不同實列名進行安裝。如圖


    4.服務器配置,服務器配置主要是服務啟動帳戶的配置,服務的帳戶名推薦使用NT AUTHORITY\SYSTEM的系統帳戶,并指定當前選擇服務的啟動類型,如圖

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


     

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

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




    posted @ 2013-01-28 06:54 RoyPayne 閱讀(2917) | 評論 (1)編輯 收藏
          死鎖是一個經典的多線程問題,因為不同的線程都在等待那些根本不可能被釋放的鎖,
    從而導致所有的工作都無法完成。假設有兩個線程,分別代表兩個饑餓的人,他們必須共享刀叉并輪流吃飯。
    他們都需要獲得兩個鎖:共享刀和共享叉的鎖。假如線程 "A" 獲得了刀,而線程 "B" 獲得了叉。
    線程 A 就會進入阻塞狀態來等待獲得叉,而線程 B 則阻塞來等待 A 所擁有的刀。
          
          讓所有的線程按照同樣的順序獲得一組鎖。這種方法消除了 X 和 Y 的擁有者分別等待對方的資源的問題。
      將多個鎖組成一組并放到同一個鎖下。前面死鎖的例子中,可以創建一個銀器對象的鎖。于是在獲得刀或叉之前都必須獲得這個銀器的鎖。
      將那些不會阻塞的可獲得資源用變量標志出來。當某個線程獲得銀器對象的鎖時,就可以通過檢查變量來判斷是否整個銀器集合中的對象鎖都可獲得。如果是,它就可以獲得相關的鎖,否則,就要釋放掉銀器這個鎖并稍后再嘗試。
      最重要的是,在編寫代碼前認真仔細地設計整個系統。多線程是困難的,在開始編程之前詳細設計系統能夠幫助你避免難以發現死鎖的問題。
    posted @ 2012-12-10 10:54 RoyPayne 閱讀(345) | 評論 (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) | 評論 (21)編輯 收藏
    XFire WebService開發快速起步


    http://lavasoft.blog.51cto.com/62575/105956/
    posted @ 2012-02-01 14:50 RoyPayne 閱讀(355) | 評論 (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) | 評論 (2)編輯 收藏

    在Session的緩存中存放的是相互關聯的對象圖。默認情況下,當Hibernate從數據庫中加載Customer對象時,會同時加載所有關聯的 Order對象。以Customer和Order類為例,假定ORDERS表的CUSTOMER_ID外鍵允許為null

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

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

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

    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語句,Hibernate最后加載了4個Customer對象和5個Order對象,在內存中形成了一幅關聯的對象圖.


    Hibernate在檢索與Customer關聯的Order對象時,使用了默認的立即檢索策略。這種檢索策略存在兩大不足: 

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

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

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

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


    對數據庫訪問還是必須考慮性能問題的, 在設定了1 對多這種關系之后, 查詢就會出現傳說中的n +1 問題。 
    1 )1 對多,在1 方,查找得到了n 個對象, 那么又需要將n 個對象關聯的集合取出,于是本來的一條sql查詢變成了n +1 條 
    2)多對1 ,在多方,查詢得到了m個對象,那么也會將m個對象對應的1 方的對象取出, 也變成了m+1

    怎么解決n +1 問題? 
    1 )lazy=true, hibernate3開始已經默認是lazy=true了;lazy=true時不會立刻查詢關聯對象,只有當需要關聯對象(訪問其屬性,非id字段)時才會發生查詢動作。 

    2)二級緩存, 在對象更新,刪除,添加相對于查詢要少得多時, 二級緩存的應用將不怕n +1 問題,因為即使第一次查詢很慢,之后直接緩存命中也是很快的。 
    不同解決方法,不同的思路,第二條卻剛好又利用了n +1 。

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

    posted @ 2012-01-30 14:20 RoyPayne 閱讀(10907) | 評論 (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>

    這個Filter會攔截所有的URL請求,并且對這些URL請求進行Spring Security的驗證。 

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

    與Acegi的配置不同,Acegi需要自行聲明一個Spring的bean來作為Filter的實現,而使用Spring Security后,無需再額外定義bean,而是使用<http>元素進行配置。 

    通過擴展Spring Security的默認實現來進行用戶和權限的管理 

    事實上,Spring Security提供了2個認證的接口,分別用于模擬用戶和權限,以及讀取用戶和權限的操作方法。這兩個接口分別是: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;
    }

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

    2.struts2.xml 配置interceptor

      2.1 定義自定義攔截器
    <interceptor name="authorityInterceptor" class="com.wasu.eis.authority.AuthorityInterceptor" /> 
      2.2 加上struts2默認攔截器,形成攔截器棧
                <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.設置為缺省的攔截器

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

    1.第一個例子:

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

    2.第二個例子:

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

    3.第三個例子:

    <%
    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 為設置缺省值

    4.第四個例子

    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頁面
          <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>對應bean里面的字段programName 
    綠色為<option value="xxx",對應bean里面的字段programid

    紫色為設定select被選中的值,s:select 會自動在 bean選中 key對應的值

    posted @ 2012-01-12 15:10 RoyPayne 閱讀(248) | 評論 (0)編輯 收藏
    工作中碰到個ConcurrentModificationException。代碼如下:
    List list = ...;
    for(Iterator iter = list.iterator(); iter.hasNext();) {
        Object obj = iter.next();
        ...
        if(***) {
            list.remove(obj);
        }
    }
    在執行了remove方法之后,再去執行循環,iter.next()的時候,報java.util.ConcurrentModificationException(當然,如果remove的是最后一條,就不會再去執行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);
        ...
    }

    這里有兩個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> {  //內部類Itr
            int cursor = 0;
            int lastRet = -1;
            int expectedModCount = modCount;

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

            public E next() {
                checkForComodification();  //特別注意這個方法
                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);  //執行remove對象的操作
                    if (lastRet < cursor)
                        cursor--;
                    lastRet = -1;
                    expectedModCount = modCount;  //重新設置了expectedModCount的值,避免了ConcurrentModificationException的產生
                } catch(IndexOutOfBoundsException e) {
                    throw new ConcurrentModificationException();
                }
            }

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


    remove(Object o)在ArrayList中實現如下:
    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
        ....
    }

    所以,產生ConcurrentModificationException的原因就是:
    執行remove(Object o)方法之后,modCount和expectedModCount不相等了。然后當代碼執行到next()方法時,判斷了checkForComodification(),發現兩個數值不等,就拋出了該Exception。
    要避免這個Exception,就應該使用remove()方法。

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


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

    Volatile 變量

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

    正確使用 volatile 變量的條件

      您只能在有限的一些情形下使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時滿足下面兩個條件:
      ● 對變量的寫操作不依賴于當前值。
      ● 該變量沒有包含在具有其他變量的不變式中。
      實際上,這些條件表明,可以被寫入 volatile 變量的這些有效值獨立于任何程序的狀態,包括變量的當前狀態。
      第一個條件的限制使 volatile 變量不能用作線程安全計數器。雖然增量操作(x++)看上去類似一個單獨操作,實際上它是一個由讀取-修改-寫入操作序列組成的組合操作,必須以原子方式執行,而 volatile 不能提供必須的原子特性。實現正確的操作需要使 x 的值在操作期間保持不變,而 volatile 變量無法實現這點。(然而,如果將值調整為只從單個線程寫入,那么可以忽略第一個條件。)
      大多數編程情形都會與這兩個條件的其中之一沖突,使得 volatile 變量不能像 synchronized 那樣普遍適用于實現線程安全。清單 1 顯示了一個非線程安全的數值范圍類。它包含了一個不變式 —— 下界總是小于或等于上界。
           
           
    清單 1. 非線程安全的數值范圍類
    @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; 

    }

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

    性能考慮

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

    正確使用 volatile 的模式

      很多并發性專家事實上往往引導用戶遠離 volatile 變量,因為使用它們要比使用鎖更加容易出錯。然而,如果謹慎地遵循一些良好定義的模式,就能夠在很多場合內安全地使用 volatile 變量。要始終牢記使用 volatile 的限制 —— 只有在狀態真正獨立于程序內其他內容時才能使用 volatile —— 這條規則能夠避免將這些模式擴展到不安全的用例。
      模式 #1:狀態標志 也許實現 volatile 變量的規范使用僅僅是使用一個布爾狀態標志,用于指示發生了一個重要的一次性事件,例如完成初始化或請求停機。
      很多應用程序包含了一種控制結構,形式為 “在還沒有準備好停止程序時再執行一些工作”,如清單 2 所示:
      清單 2. 將 volatile 變量作為狀態標志使用

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

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

    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() 中的代碼在解除對 theFlooble 的引用時,將會得到一個不完全構造的 Flooble。
      該模式的一個必要條件是:被發布的對象必須是線程安全的,或者是有效的不可變對象(有效不可變意味著對象的狀態在發布之后永遠不會被修改)。volatile 類型的引用可以確保對象的發布形式的可見性,但是如果對象的狀態在發布后將發生更改,那么就需要額外的同步。
      模式 #3:獨立觀察(independent observation)
      安全使用 volatile 的另一種簡單模式是:定期 “發布” 觀察結果供程序內部使用。例如,假設有一種環境傳感器能夠感覺環境溫度。一個后臺線程可能會每隔幾秒讀取一次該傳感器,并更新包含當前文檔的 volatile 變量。然后,其他線程可以讀取這個變量,從而隨時能夠看到最新的溫度值。
      使用該模式的另一種應用程序就是收集程序的統計信息。清單 4 展示了身份驗證機制如何記憶最近一次登錄的用戶的名字。將反復使用 lastUser 引用來發布值,以供程序的其他部分使用。
      清單 4. 將 volatile 變量用于多個獨立觀察結果的發布
    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; 

    }

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

    @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 的高級模式
      前面幾節介紹的模式涵蓋了大部分的基本用例,在這些模式中使用 volatile 非常有用并且簡單。這一節將介紹一種更加高級的模式,在該模式中,volatile 將提供性能或可伸縮性優勢。
      volatile 應用的的高級模式非常脆弱。因此,必須對假設的條件仔細證明,并且這些模式被嚴格地封裝了起來,因為即使非常小的更改也會損壞您的代碼!同樣,使用更高級的 volatile 用例的原因是它能夠提升性能,確保在開始應用高級模式之前,真正確定需要實現這種性能獲益。需要對這些模式進行權衡,放棄可讀性或可維護性來換取可能的性能收益 —— 如果您不需要提升性能(或者不能夠通過一個嚴格的測試程序證明您需要它),那么這很可能是一次糟糕的交易,因為您很可能會得不償失,換來的東西要比放棄的東西價值更低。
      模式 #5:開銷較低的讀-寫鎖策略
      目前為止,您應該了解了 volatile 的功能還不足以實現計數器。因為 ++x 實際上是三種操作(讀、添加、存儲)的簡單組合,如果多個線程湊巧試圖同時對 volatile 計數器執行增量操作,那么它的更新值有可能會丟失。
      然而,如果讀操作遠遠超過寫操作,您可以結合使用內部鎖和 volatile 變量來減少公共代碼路徑的開銷。清單 6 中顯示的線程安全的計數器使用 synchronized 確保增量操作是原子的,并使用 volatile 保證當前結果的可見性。如果更新不頻繁的話,該方法可實現更好的性能,因為讀路徑的開銷僅僅涉及 volatile 讀操作,這通常要優于一個無競爭的鎖獲取的開銷。
      清單 6. 結合使用 volatile 和 synchronized 實現 “開銷較低的讀-寫鎖”
    @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++; 

    }

    之所以將這種技術稱之為 “開銷較低的讀-寫鎖” 是因為您使用了不同的同步機制進行讀寫操作。因為本例中的寫操作違反了使用 volatile 的第一個條件,因此不能使用 volatile 安全地實現計數器 —— 您必須使用鎖。然而,您可以在讀操作中使用 volatile 確保當前值的可見性,因此可以使用鎖進行所有變化的操作,使用 volatile 進行只讀操作。其中,鎖一次只允許一個線程訪問值,volatile 允許多個線程執行讀操作,因此當使用 volatile 保證讀代碼路徑時,要比使用鎖執行全部代碼路徑獲得更高的共享度 —— 就像讀-寫操作一樣。然而,要隨時牢記這種模式的弱點:如果超越了該模式的最基本應用,結合這兩個競爭的同步機制將變得非常困難。
      結束語
      與鎖相比,Volatile 變量是一種非常簡單但同時又非常脆弱的同步機制,它在某些情況下將提供優于鎖的性能和伸縮性。如果嚴格遵循 volatile 的使用條件 —— 即變量真正獨立于其他變量和自己以前的值 —— 在某些情況下可以使用 volatile 代替 synchronized 來簡化代碼。然而,使用 volatile 的代碼往往比使用鎖的代碼更加容易出錯。本文介紹的模式涵蓋了可以使用 volatile 代替 synchronized 的最常見的一些用例。遵循這些模式(注意使用時不要超過各自的限制)可以幫助您安全地實現大多數用例,使用 volatile 變量獲得更佳性能。


    posted @ 2012-01-06 10:44 RoyPayne 閱讀(300) | 評論 (1)編輯 收藏
    主站蜘蛛池模板: 啦啦啦完整版免费视频在线观看| h视频在线观看免费完整版| 狠狠色伊人亚洲综合成人| 99久久免费观看| 亚洲AV日韩AV一区二区三曲| 亚洲一区二区三区在线观看精品中文 | 91精品手机国产免费| 亚洲乱色伦图片区小说| 亚洲日韩中文在线精品第一| 2019中文字幕在线电影免费 | 亚洲第一街区偷拍街拍| 亚洲中文字幕在线观看| 手机在线看永久av片免费| 亚洲Av永久无码精品黑人| 亚洲日韩图片专区第1页| 免费看国产曰批40分钟| 3d成人免费动漫在线观看| 免费一级做a爰片久久毛片潮| 久久精品国产亚洲AV高清热| 免费一区二区三区四区五区| 精品国产无限资源免费观看| 四虎永久在线精品免费一区二区 | 亚洲国产一区二区三区青草影视| 黄a大片av永久免费| 曰批全过程免费视频播放网站 | 亚洲AV无码精品色午夜果冻不卡 | 国产一级婬片A视频免费观看| 亚洲乱码一区二区三区国产精品| 日本亚洲成高清一区二区三区| 免费看的成人yellow视频| 91精品成人免费国产片| 日韩免费观看一区| 一区二区三区视频免费| 亚洲国产欧美国产综合一区| 亚洲精品午夜久久久伊人| 亚洲国产成人一区二区精品区| 免费一级大黄特色大片| 好大好硬好爽免费视频| 久久久久久精品成人免费图片 | 久久受www免费人成_看片中文| 最近免费中文字幕MV在线视频3|