我思故我強

          Java線程之同步化(Synchronized)

          1.? 如果一個對象所持有的數據可以被多線程同時共享存取,必須考慮到數據同步的問題。所謂數據同步指的是兩份數據的整體性和一致性。數據在多線程下共享時容易由于同時多個線程可能更新同一個對象的信息,而造成對象數據的不同步,因為數據的不同步可能引發(fā)的錯誤通常不易察覺,而且可能是在程序執(zhí)行了幾千幾萬次之后,才會發(fā)生錯誤。這通常會發(fā)生在產品已經上線之后,甚至是程序已經執(zhí)行了幾年之后。

          2. 舉個簡單的例子,設計了一個PersonalInfo類:???

          Java代碼?
          1. package ?ysu.hxy; ??
          2. ??
          3. public ? class ?PersonalInfo? ??
          4. { ??
          5. ???? private ?String?name; ??
          6. ???? private ?String?id; ??
          7. ???? private ? int ?count; ??
          8. ??
          9. ???? public ?PersonalInfo() ??
          10. ????{ ??
          11. ????????name?=? "nobody" ; ??
          12. ????????id?=? "N/A" ; ??
          13. ????} ??
          14. ??
          15. ???? public ? void ?setNameAndID(String?name,String?id) ??
          16. ????{ ??
          17. ???????? this .name?=?name; ??
          18. ???????? this .id?=?id; ??
          19. ???????? if (!checkNameAndIDEqual()) ??
          20. ????????{ ??
          21. ?????????????System.out.println(count?+? ")?illegal?name?or?ID..." ); ??
          22. ????????} ??
          23. ????????count?++; ??
          24. ????} ??
          25. ??
          26. ???? private ? boolean ?checkNameAndIDEqual(){ ??
          27. ???????? return ?(name.charAt( 0 )?==?id.charAt( 0 ))??? true : false ; ??
          28. ????} ??
          29. }??

          ?單就這個類本身而言,它并沒有任何的錯誤,但如果它被用于多線程的程序中,而且同一個對象被多個線程存取時,就會有可能發(fā)生錯誤。下面是一個簡單的測試程序,看看PersonalInfo類在多線程共享數據下會發(fā)生什么問題。

          Java代碼?
          1. package ?ysu.hxy; ??
          2. ??
          3. public ? class ?PersonalInfoTest? ??
          4. { ??
          5. ???? public ? static ? void ?main(String[]?args)? ??
          6. ????{ ??
          7. ???????? final ?PersonalInfo?person?=? new ?PersonalInfo(); ??
          8. ??
          9. ???????? //假設會能兩個線程可能更新person對象? ??
          10. ????????Thread?thread1?=? new ?Thread( new ?Runnable()?{ ??
          11. ???????????? public ? void ?run()?{ ??
          12. ???????????????? while ( true ){ ??
          13. ????????????????????person.setNameAndID( "Justin?Lin" , "J.L" ); ??
          14. ????????????????} ??
          15. ????????????} ??
          16. ????????}); ??
          17. ??
          18. ????????Thread?thread2?=? new ?Thread( new ?Runnable()?{ ??
          19. ???????????? public ? void ?run()?{ ??
          20. ???????????????? while ( true ){ ??
          21. ????????????????????person.setNameAndID( "Shang?Hwang?Lin" , "S.H" ); ??
          22. ????????????????} ??
          23. ????????????} ??
          24. ????????}); ??
          25. ??
          26. ????????System.out.println(); ??
          27. ??
          28. ????????thread1.start(); ??
          29. ????????thread2.start(); ??
          30. ????} ??
          31. }??

          ?

          執(zhí)行結果:

          D:\hxy>java ysu.hxy.PersonalInfoTest
          開始測試...
          23466451) illegal name or ID...
          78044494) illegal name or ID...
          101630476) illegal name or ID...
          106496643) illegal name or ID...
          145330181) illegal name or ID...
          169674022) illegal name or ID...
          174072203) illegal name or ID...
          214717201) illegal name or ID...
          219668799) illegal name or ID...
          240921750) illegal name or ID...
          265875722) illegal name or ID...
          270920923) illegal name or ID...
          281256783) illegal name or ID...

          這個程序出現了錯誤,在23466451次的setNameAndID()執(zhí)行時就開始了。如果程序完成并開始應用于實際場合之后,這個時間點可能是幾個月甚至是幾年之后。問題出在這里:

          Java代碼?
          1. public ? void ?setNameAndID(String?name,String?id) ??
          2. ????{ ??
          3. ???????? this .name?=?name; ??
          4. ???????? this .id?=?id; ??
          5. ???????? if (!checkNameAndIDEqual()) ??
          6. ????????{ ??
          7. ?????????????System.out.println(count?+? ")?illegal?name?or?ID..." ); ??
          8. ????????} ??
          9. ????????count?++; ??
          10. ????}??

          ????? 雖然傳遞給setNameAndID()的變量并沒有問題,在某個時間點時,thread1設定了Justin Lin、J.L給name和id,在進行if測試的前一刻,thread2可能此時剛好調用setNameAndID("Shang Hwang","S.H")。在name被設定為Shang HWang時,checkNameAndIDEqual()開始執(zhí)行,此時name等于Shang HWang,而id還是J.L。所以,checkNameAndIDEqual()就會返回false,結果就顯示了錯誤信息。

          ?????? 必須同步數據對對象的更新,方法在有一個線程正在設定person對象的數據時,不可以被另一個線程同時進行設定??梢允褂胹ynchronized關鍵詞來進行這個動作。

          Java代碼?
          1. public ? synchronized ? void ?setNameAndID(String?name,String?id) ??
          2. ????{ ??
          3. ???????? this .name?=?name; ??
          4. ???????? this .id?=?id; ??
          5. ???????? if (!checkNameAndIDEqual()) ??
          6. ????????{ ??
          7. ?????????????System.out.println(count?+? ")?illegal?name?or?ID..." ); ??
          8. ????????} ??
          9. ????????count?++; ??
          10. ????}??

          ?這是synchronized關鍵詞的一個使用方式,用于方法上讓方法的范圍內都成為被同步化區(qū)域。被同步化區(qū)域在有一個線程占據時就像一個禁區(qū),不允許其他線程進入。由于同時間只能有一個線程在被同步化區(qū)域,所以更新共享數據時,就像單線程程序在更新數據一樣,以保證對象中的數據會與給定的數據同步。

          ? sychronized的設定不只可用于方法上,也可以用于限定某個程序區(qū)塊上被同步化區(qū)域。例如:?

          Java代碼?
          1. public ? void ?setNameAndID(String?name,String?id) ??
          2. ??{? //同步某個程序區(qū)塊 ??
          3. ??????? synchronized ( this ) ??
          4. ???{ ??
          5. ??????? this .name?=?name; ??
          6. ??????? this .id?=?id; ??
          7. ??????? if (!checkNameAndIDEqual()) ??
          8. ??????????{ ??
          9. ???????????????System.out.println(count+ ")?illegal?name?or?ID..." ); ??
          10. ??????????} ??
          11. ???} ??
          12. }??

          ?? 這個程序片段的意思是,在線程執(zhí)行到synchronized設定的被同步化區(qū)塊時鎖定當前對象,這樣就沒有其他線程可以來執(zhí)行這個被同步化區(qū)塊。這個方式可以應用于您不想鎖定整個方法區(qū)塊,而只是想在更新共享數據時再確保對象與數據的同步化。由于只鎖定方法中的某個區(qū)塊,在執(zhí)行完區(qū)塊后即釋放對對象的鎖定,以便讓其他線程能有機會對對象進行操作,相對于鎖定整個方法區(qū)塊效率較高。

          ?? 也可以標示某個對象要求同步化。例如在多線程中存取同一個ArrayList對象時,由于ArrayList并沒有實現數據存取時的同步化,所以當它使用多線程環(huán)境時,必須注意多個線程存取同一個ArrayList時,有可能發(fā)生兩個以上的線程將數據存入ArrayList的同一個位置,造成數據的相互覆蓋。為了確保數據存入時的正確性,可以在存取ArrayList對象時要求同步化。例如:

          Java代碼?
          1. //arraylist參考至一個ArrayList的一個實例 ??
          2. synchronized (arraylist) ??
          3. { ??
          4. ?????arrayList.add( new ?SomeClass()); ??
          5. }??

          ?同步化確保數據的同步,但所犧牲的就是在于一個線程占據同步化區(qū)塊,而其他線程等待它釋放區(qū)塊執(zhí)行權時的延遲。這在線程少時可能看不出來,但在線程多的環(huán)境中必然造成一定的效率問題(例如大型網站的多人聯機時)。

          posted on 2009-10-14 11:52 李云澤 閱讀(446) 評論(0)  編輯  收藏 所屬分類: 面試筆試相關的

          主站蜘蛛池模板: 宁城县| 鸡西市| 河北区| 肃北| 大宁县| 扶余县| 通化市| 乐山市| 景谷| 那坡县| 东兰县| 古浪县| 酉阳| 门源| 馆陶县| 霍林郭勒市| 大理市| 华蓥市| 治县。| 东安县| 黄梅县| 平乐县| 华容县| 庆安县| 修文县| 樟树市| 陇南市| 保靖县| 溧阳市| 纳雍县| 黄骅市| 安龙县| 南汇区| 新津县| 历史| 宁国市| 中牟县| 拉萨市| 翁牛特旗| 美姑县| 那坡县|