亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

并發(fā)中的遍歷

系統(tǒng) 1881 0

???? 在開發(fā)多線程并發(fā)的程序時,對列表進行遍歷是一個很常見的操作。比如說在觀察者模式中,當某個事件發(fā)生時,就需要通知到對應的觀察者進行事件的處理,這里就需要對觀察者列表進行遍歷,逐一觸發(fā)觀察者進行事件的處理。那么,如何保證并發(fā)中的遍歷操作的原子性呢?大概有下面幾種方式:

1. 首先,最容易想到的肯定是使用JAVA內(nèi)置的同步機制-synchronized,把整個遍歷操作當作一個原子操作。

    synchronized(lock)
{
    for(Observer ob:observers)
    {
          //trigger event
          ob.update(event);
    }
}
  

?

這里使用的鎖對象-lock,應該是和對觀察者列表進行增加刪除操作時使用的鎖是同一個。采用這種方式,如果觀察者列表比較少而且觀察者進行事件的處理時間比較短的時候,是可接受的。如果觀察者列表變的很大或者其中某幾個觀察者進行事件的處理占時比較長的時候,那么就會引發(fā)并發(fā)的liveness問題,從而引起性能的下降。

?

2.索引訪問

??針對第一種遍歷出現(xiàn)的問題,我們可以通過減少synchronized的范圍來進行優(yōu)化。每當我們看到synchronized塊的時候,我們要問問自己,synchronized塊保護的是什么?很明顯,上面保護的是observers列表,保證對該列表并發(fā)訪問時數(shù)據(jù)的正確性。也就是說,對于ob.update(event),根本不需要進行保護。從而出現(xiàn)了Doug Lea所說的索引訪問:

    Observer ob=null;
for(int i=0;true;i++)
{
     synchronized(observers)
     {
         if(i<observers.size())
            ob=observers.get(i);
         else
            break;
     }

     //下面update調(diào)用不需要同步
   ob.update(event);
}
  

??? 雖然這種方式對性能有所提升,但是有可能會出現(xiàn)這樣的問題,如果在遍歷過程中,對observers列表進行刪除,則有可能出現(xiàn)被刪除的Observer沒有機會進行事件的觸發(fā),或者對observers列表進行增加一個相同的元素,而observers本身就允許增加相同元素的時候,那么同一個Observer可能會對同一事件進行兩次處理。而對于第一種遍歷方式的另外一種改進,則是通過在持有鎖的情況下,復制一份observers列表,然后在不持有鎖的情況下,對observers列表中的每個observer進行事件的通知:

    Object[] tempObservers=null;
synchronized(observers)
{
    tempObservers=Arrays.copyOf(observers,observers.length);
}

for(Observer ob:tempObservers)
    ob.update(event);

  

?

?

3.Fail-fast

?? 如果不允許第2種遍歷方式出現(xiàn)的問題,那么可以通過使用Fail-fast模式來進行強制避免。Fail-fast模式經(jīng)常出現(xiàn)在java的Iterator中。在Fail-fast模式中,每個列表維護一個int型的版本變量,每次對這個列表進行更新操作都會使這個版本變量加1。

    public class List
{
int version;

public synchronized void add(Object obj)
{
    //add object
    array[cursor++]=obj;    
    version++;
}

public synchronized  void remove(int index)
{
     //remove
     array[index]=null;
     version++;
}

//其余略

}

  

?? 而在創(chuàng)建一個Iterator時,會將當前的版本變量保存,在通過Iterator進行遍歷的時候,會每次都將Iterator內(nèi)部保存的版本變量和List列表維護的版本變量進行比較,如果不相等,則表示有線程對當前的List列表進行了更新操作,那么Iterator的遍歷方式會拋出一個異常進行中止遍歷。

    public class List
{
   int version;
  
   ....

    public Iterator iterator()
    {
          return new ListIterator();
    }
 
    //inner class
    class ListIterator implements Iterator
    {
         int iteratorVersion;
         public ListIterator()
         {
             iteratorVersion=version;
         }

         public boolean hasNext()
         {
              synchronized(List.this){
                 if(iteratorVersion!=version)
                      throw new RuntimeException();
                  //check if the next element exists
              }
         }

         public Object next()
         {
              synchronized(List.this){
                 if(iteratorVersion!=version)
                      throw new RuntimeException();
                  //return the next element
               }
          }
}
    

  

? ? 如果你看過JDK的Iterator實現(xiàn),你就會發(fā)現(xiàn)JDK中提供的大多數(shù)Iterator都不是同步的,即使是使用Collections.synchronizedList()后的list,這也就導致了我們常常在使用JDK提供的Iterator時,要自己考慮遍歷時的同步,否則會出現(xiàn)這樣的問題,iterator的遍歷是在一個線程,而對集合進行更新操作的是在另一個線程,那么,由于iterator遍歷的過程沒有同步,而version變量也不是violate,這樣就沒法保證version變量在并發(fā)中的可見性從而引起問題。而上述的實現(xiàn)了一個有鎖的版本。

???? 其實,上面這個synchronized版本的iterator可以進一步優(yōu)化,可以將version變量聲明為violate,從而將所有的的鎖給去掉。雖然Fail-fast模式的遍歷可以保證并發(fā)遍歷操作時數(shù)據(jù)的正確性,但是這種遍歷方式很不友好,特別是在大并發(fā)的情況下,F(xiàn)ail-fast遍歷拋出異常中止的機率很高,試想下,如果在觀察者中使用Fail-fast的遍歷方式來通知事件的發(fā)生,那么在大并發(fā)的情況下,一件事件的發(fā)生并不保證會通知到所有的觀察者,這樣有可能就造成了事件的丟失,這個問題導致了Fail-fast的遍歷方式的使用業(yè)務場景會比較窄。

??

4.copy on write

???而對于copy on write方式,其原理是,每次在對集合進行更新操作的時候,都會對底層的數(shù)組進行拷貝。比如說add,remove操作。

    public class CopyOnWriteList
{
     
     public synchronized void add(Object obj)
     {
         Object[] newArray=Arrays.copyOf(oldArray,oldArray.length+1);
         newArray[oldArray.length]=obj;
         oldArray=newArray;
     }

    .....
}
  

??? 那么就可以在進行遍歷操作的時候,不需要加鎖來保證同步。

??

    public class CopyOnWriteList
{
    Object[] oldArray;
    ....

    public Iterator iterator()
    {
         return new CopyOnWriteIterator(oldArray);
    }
    
    public CopyOnWriteIterator implements Iterator
    {
         private Object[] iteratorArray;
         private int cursor;
         public CopyOnWriteIterator(Object[] array)
         {
              iteratorArray=array;
         }

         //不需要加鎖
      public boolean hasNext()
         {
             return cursor++<iteratorArray.length;
         }

          //不需要加鎖
       public Object next()
          {
              return iteratorArray[cursor];
          }
}
  

???雖然說copy on write的方式避免了遍歷時加鎖的問題,但是這種方式只適用于對于集合更新操作比較少,但遍歷使用場景比較多的情況下,?否則頻繁的COPY操作也會使性能下降。這種方式現(xiàn)在廣泛的應用于觀察者模式中,因為觀察者模式更多的是進行一個事件的通知(即遍歷集合),而不是增加/刪除觀察者。

?

5.鏈表-通過對add,remove等更新操作分別進行特殊處理,使得遍歷不加鎖。

?? 這種實現(xiàn)方式?jīng)]有鎖,也沒有violate變量,而是通過維護一個單向鏈表,并分別對Add,Remove操作進行一些額外的限制。對于Add操作來說,新加入的節(jié)點必須加到原先鏈表頭結點之前,新加入的節(jié)點變成新的鏈表頭節(jié)點:

???
并發(fā)中的遍歷
?

?????通過這樣的方式,在遍歷過程中進行節(jié)點的增加操作也不會有并發(fā)問題,而對應的remove操作則需要復制被刪除節(jié)點之前的所有節(jié)點,并與被刪除的節(jié)點后面的節(jié)點關聯(lián)起來,如果要刪除的節(jié)點是最后一個節(jié)點,則相當于復制了整個鏈表。
?????????
并發(fā)中的遍歷
?
??????? 如果在遍歷過程中進行刪除,也不會有并發(fā)問題,原先的遍歷會一直執(zhí)行,新的遍歷會從新復制的節(jié)點開始。因為這里的刪除操作是對原來的節(jié)點進行了復制,而原先的節(jié)點在遍歷結束后被GC回收掉。

并發(fā)中的遍歷


更多文章、技術交流、商務合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 四虎国产在线观看 | 久久午夜激情 | h片在线观看网站 | 免费xxx| 亚洲高清网站 | 久久尹人 | 视频一区中文字幕 | 日韩欧美国产高清在线观看 | 国产亚洲欧美成人久久片 | 日韩视频 中文字幕 视频一区 | 亚洲欧美综合在线观看 | 四虎影院在线观看网站 | 台湾一级毛片免费播放 | 国产日韩精品一区二区 | 国产福利专区精品视频 | 国产女人综合久久精品视 | 伊人网伊人 | 一 级做人爱全视频在线看 一a级毛片 | 中国在线播放精品区 | 欧美性色欧美a在线观看 | 色综合91久久精品中文字幕 | 欧美日韩久久 | 欧美日韩国产一区三区 | 亚洲久久影院 | 色综合久久88色综合天天小说 | 国产精品好好热在线观看 | 精品国产999 | 国语国产真人对白毛片 | 亚洲啊v| 成人欧美一区二区三区在线观看 | 米奇777第四久久久99 | 日韩美女va在线毛片免费知 | 97碰公开在线观看免费视频 | 亚洲一区二区精品 | 毛片免费视频 | 天天操综合网 | 亚洲男人的天堂久久无 | 久久久99精品免费观看 | 日韩精品中文字幕在线观看 | 伊人久久久久久久久香港 | 亚洲精品美女在线观看 |