深入列表遍曆問題,並分析spring和tomcat中觀察者模式的實現

來源:互聯網
上載者:User

列表的遍曆有兩種方式,一種是採用for迴圈,如下所示:

List list=new ArrayList();
for(int i=0;i<list.size();i++)...{
//...
}

還有一種是採用Iterator介面 ,如下所示:

Iterator ite=list.iterator();
while(ite.hasNext())...{//...
}

那麼這兩種方式有什麼差別呢?答案是在順序執行的程式中,他們沒有差別;但是在並行程式中有差別。如果在遍曆的過程中有另外一個線程修改了list,那麼採用for迴圈其執行結果是不確定的,而採用Iterator會快速失敗(fast-fail)並拋出ConcurrentModificationException。所以在通常情況下,優先使用Iterator遍曆集合對象。

有時候我們需要在遍曆過程中保證集合不被修改,這就需要對集合進行同步。

    synchronized(list)...{
        Iterator ite=list.iterator();
        while(ite.hasNext())...{
         //...
        }
    }

上面這種方式需要在遍曆過程中完全鎖住被訪問的list對象,如果遍曆過程耗時較長容易導致效能下降和死結。所以有時可以採用臨時拷貝的方法,在拷貝後的私人臨時集合上執行遍曆操作。

            Object[] snapshot;
            synchronized (list) ...{
                snapshot = new Object[list.size()];
                for (int i = 0; i < snapshot.length; ++i)
                    snapshot[i] = list.get(i);
            }
            for (int i = 0; i < snapshot.length; ++i) ...{
                    //...
            }

下面考慮一個實際的例子,就是observer模式。一個目標對象有多個觀察者,當目標狀態發生變化時,它向各個觀察者發出通知。下面是tomcat5中ContainerBase類的一個方法:

    public void fireContainerEvent(String type, Object data) ...{

        if (listeners.size() < 1)
            return;
        ContainerEvent event = new ContainerEvent(this, type, data);
        ContainerListener list[] = new ContainerListener[0];
        synchronized (listeners) ...{
            list = (ContainerListener[]) listeners.toArray(list);
        }
        for (int i = 0; i < list.length; i++)
            ((ContainerListener) list[i]).containerEvent(event);

    }

可見它採用的是臨時拷貝的方法。
下面是spring中ApplicationEventMulticasterImpl類的一個方法:

    public void onApplicationEvent(ApplicationEvent e) ...{
        Iterator i = eventListeners.iterator();
        while (i.hasNext()) ...{
            ApplicationListener l = (ApplicationListener) i.next();
            l.onApplicationEvent(e);
        }
    }

可見spring採用的是未同步的Iterator方法。

我認為Spring的寫法是不恰當的。這涉及到伺服器端應用和用戶端應用異常處理方式的問題。對於用戶端應用,完全可以採用不同步的Iterator方式。當異常發生時提示操作者是放棄操作,還是重試。但是對於伺服器端應用,必須保證在遍曆的過程中不發生異常。Spring作為一個通用的組件管理架構,當然不能假定其使用的場合。

 後記:java5中的java.util.concurrent包中的集合類,提供了另外一種形式的weakly-consistent iterator。它不同於傳統的fast-fail Iterator。they promise to be thread safe, but don't promise whether you will see any updates made to the collection since the iterator was constructed (e.g., you might see an added element, or you might not).

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.