Android中workerthread與UIthread同時訪問同一資源造成ConcurrentModificationException解決參考
個人總結,若有問題,希望大家不吝指教,在此感謝。
專案中遇到一個ConcurrentModificationException異常,這種異常比較蛋疼,一般兩個執行緒同時訪問一個資源造成的,一個再改,一個再做別的,然後就不同步了。
Log資料中只給出一個點,不方便查詢另一個問題點。這類必須解決的就是兩個執行緒對同一個資源(我們這是一個HashMap)同步的問題,一個方式就是加鎖解決,這是一個總方針。但是加鎖如果加不好,就會造成UIthread的執行緒因為在鎖那裡等的時間比較長而造成ANR,當然這種情況不常見,因為你的超過5秒才能ANR,但是是有這個可能的,我們遇到了……
然後就是思考了兩個方案,一個是做一個高優先順序的執行緒(參考android執行緒優先順序就能知道哪個合適,有倆都可以)來對UIthread裡面對資源的訪問提出來,這樣不會ANR,但是專案大,地方多,這麼幹結構都得變,還有就是那種特別需要及時相應的地方(UI介面上的滑動動畫啥的),擔心這麼做會有一定的延時。然後就放棄了,改動貌似有點大。
第二個方案就是做備份了,那備份給UIthread去使用。何時做、咋做備份又是個問題。然後就各種參考,這裡不得不說,Android原始碼還是很碉堡的,最起碼比我見過的一些大一點的專案程式碼要好。
給出一段程式碼,下面一段程式碼是桌面原始碼launcherModle裡面的一段程式碼。
程式碼中sBgWorkspaceItems、sBgAppWidgets就是workerThread和UIthread都可能訪問到的資源。在這段中做了兩個備份,Runnable中用的備份。加了一個鎖,只鎖一小段程式碼,基本不會造成ANR。這就是一個原則,如果是workerThread和UIthread都可能訪問到的資源,那麼對這類資源加鎖儘量短。看了程式碼大家應該就知道怎麼搞好了。
/** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */ void unbindWorkspaceItemsOnMainThread() { // Ensure that we don't use the same workspace items data structure on the main thread // by making a copy of workspace items first. final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>(); final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>(); synchronized (sBgLock) { tmpWorkspaceItems.addAll(sBgWorkspaceItems); tmpAppWidgets.addAll(sBgAppWidgets); } Runnable r = new Runnable() { @Override public void run() { for (ItemInfo item : tmpWorkspaceItems) { item.unbind(); } for (ItemInfo item : tmpAppWidgets) { item.unbind(); } } }; runOnMainThread(r); }