背景


          阿里云上有個阿里巴巴編碼規(guī)范認(rèn)證,我估算一下時間成本很低,多個認(rèn)證也沒什么壞處,就花了1分錢報了個名。這個認(rèn)證報名后就可以下載鏈接下的編碼規(guī)范,然后參加個考試應(yīng)該就OK了。?


          共48頁的規(guī)范實際上每讀一遍都是要花一些時間的,因為每讀一遍就會發(fā)現(xiàn)上面有些東西我不信。我需要去證明。過去證明過的因為JDK版本升級迭代有可能需要繼續(xù)證明。下面是其中的一些證明過程。

          ?

          案例1

          規(guī)范原文

          【強制】不要在foreach循環(huán)里進行元素的remove/add操作。remove元素請使用Iterator方式,如果并發(fā)操作需要對Iterator對象加鎖。

          正例:

          List<String> list = new ArrayList<>();

          list.add("1");

          list.add("2");

          Iterator<String>?iteraot = list.interator();

          while(iterator.hasNext()){

          ????String item =?iterator.next();

          ? ??if(刪除元素的條件) {

          ? ? ? ? ??iterator.remove();

          ? ??}

          }

          反例:

          for(String item : list) {

          ??????if("1".equals(item))?{

          ? ? ? ? ? ? ?list.remove(item);

          ? ? ? }

          }

          說明:以上代碼的執(zhí)行結(jié)果肯定會出乎大家的意料,那么試一下把"1"換成"2",會是同樣的結(jié)果嗎?

          證明

          1.先按照反例例文運行測試(test1)



          list里兩個元素,remove掉一個,剩下1個。這應(yīng)該是符合大多數(shù)人預(yù)期的。

          2.按照說明把"1"換成"2"運行測試(test2)



          這里沒有按照預(yù)期remove掉"2",而是拋出了并發(fā)修改異常。點擊到異常的地方

          3.根據(jù)異常提示。找到拋出異常代碼的地方查看是哪個方法拋出異常:



          4.對源碼做一個解析:

          拋出并發(fā)修改異常的條件是modCount!=expectedModCount。


          5.根據(jù)這個條件,我做一個推測:在一個操作里把這兩者的值改的不一樣了,因為這里調(diào)用了remove修改方法。我自然就推測是remove方法做的修改,來看remove方法的源碼:





          6.果然,源碼中將modCount++,但是expectedModCount并沒有修改。證明了推測。運行完remove后需要判斷for(String
          item : list) ,這時候調(diào)用了迭代器的next方法。這樣我理解了上面test2里為什么會拋出異常。那么再來思考下test1為什么不拋出異常呢?

          7.我們來debug一下test1的情況1

          運行完remove方法后,可看到這時候modCount!=expectedModCount,但是這時候只執(zhí)行了hasNext(),判斷了cursor !=
          size,這時候不會執(zhí)行next方法,所以不會產(chǎn)生異常。而下面再用到list時迭代器是新的迭代器,會把modCount=expectedModCount;



          結(jié)論


          如果list在for循環(huán)里調(diào)用remove方法是會拋出并發(fā)修改異常的,但是如果只修改了第1個就返回的情況是個例外,因為這時候不會調(diào)用next方法判斷modCount和expectedModCount是否相等。


          使用代碼規(guī)范推薦的迭代器,底層remove方法會將modCount和expectedModCount一起修改,所以單線程不會有并發(fā)問題,作為類的成員變量,多線程情況下被修改就不確定了。

          思考題

          下面代碼的執(zhí)行結(jié)果是多少?



          案例2

          規(guī)范原文


          【強制】在JDK7版本及以上,Comparotor實現(xiàn)類要滿足如下三個條件,不然Arrays.sort、Collections.sort會拋IllegalArgumentException異常。

          說明:三個條件如下

          1)x、y的比較結(jié)果和y、x的比較結(jié)果相反。

          2)x>y, y>z,則x>z。

          3)x=y,則x,z比較結(jié)果和y,z比較結(jié)果相同。

          反例:下例中沒有處理相等的情況,交換兩個對象判斷結(jié)果并不互反,不符合第一個條件,在實際使用中可能會出現(xiàn)異常。

          new?Comparotor<Student>()?{

          ????@Override

          ????public?int compare(Student o1, Student o2)?{

          ????????? ?return?o1.getId()>o2.getId()?1:-1;

          ????}

          }

          證明

          1.我們先來看看反例在實際使用中會拋出什么異常。



          ?

          ?




          2.測試發(fā)現(xiàn)不論是Collections.sort還是Arrays.sort都拋出錯誤說必須實現(xiàn)Comparable接口而不是Comparator接口。而Comparable接口是不需要滿足規(guī)范里所說的自反性、傳遞性和對稱性的。

          那為什么規(guī)范里會這么說呢?


          3.我查了Collections類的源碼,確實有幾個方法用到了Comparator類。包括反轉(zhuǎn)、二分查找、最大值、最小值和幾個sort等。后面的原來sort是可以后面接Comparator參數(shù)的。



          4. 然而我用源碼的兩個參數(shù)形式傳入后,運行了幾個例子并沒有拋出非法參數(shù)異常。于是我又在源碼中找線索。


          Collections.sort底層用了Arrays.sort,Arrays.sort底層用了TimSort,TimSort有兩處會拋出這個異常,看源碼是在二分查找merge結(jié)果的時候。



          5.使用這個sort果然是發(fā)生了非法參數(shù)異常。



          6.具體為什么會發(fā)生異常,我打了斷點,使用debug跟了一下TimSort源碼,大體是有部分排序使用了if(x<y) else
          判斷,又一些方法里使用了if(x<=y)來判斷。這兩個結(jié)果對于等于的情況是沖突的。這時候會發(fā)生異常。

          總結(jié)

          實現(xiàn)Comparator的compare方法要滿足自反性、對稱性、傳遞性。

          案例3

          規(guī)范原文





          分析


          1.從上面總結(jié)來看線程安全的Map的key和value都不能為null。線程不安全的可以為null。大家都知道m(xù)ap的key要進行hash。對null進行hash不會空指針嗎?

          帶著這個疑問,打開HashMap的源碼看到hash方法有對null做判斷,如果null則hash值為0。所以不會NPE



          ?

          2.TreeMap的put方法沒有對key做任何的判斷,然后會調(diào)用compare方法,這里會拋出NPE



          3.那么對于key如果不做特殊處理,肯定是要拋出NPE的,應(yīng)該沒有什么疑問了。為什么有的value為空也會NPE呢?



          從上面源碼可知道ConcurrentHashMap就是這么處理的,算是強制。

          ?

          4.而Hashtable也是強制。



          ?


          5.為什么線程安全的容器要設(shè)計成key和value不能為null呢?在網(wǎng)上找到了類設(shè)計者Lea的原話,主要表達(dá)的意思是因為map需要實現(xiàn)containsKey和containsValue方法。這個方法對于null的情況實際上是用get(XX)來實現(xiàn)的,如果為null就不好區(qū)分到底是因為不存在還是值就是null。

          6.而線程不安全的就是按單線程處理,下面是TreeMap里containsValue的處理,如果為輸入為null,并且有個對象值為null就是true了。

          總結(jié)

          四種常用map中線程安全的Map的key和value都不能為null。線程不安全的value都可以為null。TreeMap的key不能為null。

          案例4

          規(guī)范原文?

          【強制】多線程并行處理定時任務(wù)時,Timer?運行多個?TimeTask?時,只要其中之一沒有捕獲
          拋出的異常,其它任務(wù)便會自動終止運行,如果在處理定時任務(wù)時使用ScheduledExecutorService?則沒有這個問題。?

          證明

          1.先讓Timer?運行多個?TimeTask,讓其中之一沒有捕獲 拋出的異常



          這段代碼的意思是在10秒內(nèi)運行兩個定時任務(wù),其中一個定時任何每10ms做前后打印。另外一個拋出異常,結(jié)果拋出異常后兩個都停止了。

          2.從Timer源代碼可知,本質(zhì)上多個任務(wù)通過一個隊列來維護。處理的時候整個過程整體try catch。那么一個出異常整個過程都停止了。

          3.再驗證使用ScheduledExecutorService的情況, 可看到拋出異常的線程運行了一次之后就停止了,另外一個線程一直繼續(xù)運行。



          4. 從源碼可知如果一個工作線程出現(xiàn)了問題會直接從工作隊列里移除,不影響其他的。

          ?

          總結(jié)

          ScheduledExecutorService相比Timer能避免多個任務(wù)之間的出現(xiàn)問題時的副作用。

          案例5

          規(guī)范原文

          【強制】使用工具類Arrays.asList()把數(shù)組轉(zhuǎn)換成集合時,不能使用其修改集合相關(guān)的方 法,它的 add/remove/clear 方法會拋出
          UnsupportedOperationException 異常。說明:asList 的返回對象是一個 Arrays
          內(nèi)部類,并沒有實現(xiàn)集合的修改方法。Arrays.asList 體現(xiàn)的是適 配器模式,只是轉(zhuǎn)換接口,后臺的數(shù)據(jù)仍是數(shù)組。

          String[] str = new String[] { "yang", "hao" };

          List list = Arrays.asList(str);第一種情況:list.add("yangguanbao");
          運行時異常。第二種情況:str[0] = "changed"; 也會隨之修改,反之亦然。

          證明

          1.Arrays.asList()把數(shù)組轉(zhuǎn)換成集合后添加元素,測試運行,果然拋出異常




          跟蹤源碼可知道雖然asList生成的是ArrayList,但它并不是java.util.ArrayList,而是Arrays里自定義的。這個類不支持這些更新操作。



          總結(jié)

          小心集合類中返回一個子集或者轉(zhuǎn)換類型的操作,可能返回的是內(nèi)部定義的類,不是我們平時用的類,這些類中對一些操作做了限制。

          思考題

          下面測試類體現(xiàn)了規(guī)范的哪一條?

          ?

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點信息
          問題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                wwwwwwww在线观看 | 3p一女两男做爰免费观看 | 91精品国产综合久久久蜜臀酒店 | 日韩中文字幕一区二区三区 | 欧美肥妇片 |