<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我思故我強(qiáng)

    Java線程之同步化(Synchronized)

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

    2. 舉個(gè)簡(jiǎn)單的例子,設(shè)計(jì)了一個(gè)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. }??

    ?單就這個(gè)類本身而言,它并沒有任何的錯(cuò)誤,但如果它被用于多線程的程序中,而且同一個(gè)對(duì)象被多個(gè)線程存取時(shí),就會(huì)有可能發(fā)生錯(cuò)誤。下面是一個(gè)簡(jiǎn)單的測(cè)試程序,看看PersonalInfo類在多線程共享數(shù)據(jù)下會(huì)發(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. ???????? //假設(shè)會(huì)能兩個(gè)線程可能更新person對(duì)象? ??
    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í)行結(jié)果:

    D:\hxy>java ysu.hxy.PersonalInfoTest
    開始測(cè)試...
    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...

    這個(gè)程序出現(xiàn)了錯(cuò)誤,在23466451次的setNameAndID()執(zhí)行時(shí)就開始了。如果程序完成并開始應(yīng)用于實(shí)際場(chǎng)合之后,這個(gè)時(shí)間點(diǎn)可能是幾個(gè)月甚至是幾年之后。問題出在這里:

    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()的變量并沒有問題,在某個(gè)時(shí)間點(diǎn)時(shí),thread1設(shè)定了Justin Lin、J.L給name和id,在進(jìn)行if測(cè)試的前一刻,thread2可能此時(shí)剛好調(diào)用setNameAndID("Shang Hwang","S.H")。在name被設(shè)定為Shang HWang時(shí),checkNameAndIDEqual()開始執(zhí)行,此時(shí)name等于Shang HWang,而id還是J.L。所以,checkNameAndIDEqual()就會(huì)返回false,結(jié)果就顯示了錯(cuò)誤信息。

    ?????? 必須同步數(shù)據(jù)對(duì)對(duì)象的更新,方法在有一個(gè)線程正在設(shè)定person對(duì)象的數(shù)據(jù)時(shí),不可以被另一個(gè)線程同時(shí)進(jìn)行設(shè)定。可以使用synchronized關(guān)鍵詞來進(jìn)行這個(gè)動(dòng)作。

    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關(guān)鍵詞的一個(gè)使用方式,用于方法上讓方法的范圍內(nèi)都成為被同步化區(qū)域。被同步化區(qū)域在有一個(gè)線程占據(jù)時(shí)就像一個(gè)禁區(qū),不允許其他線程進(jìn)入。由于同時(shí)間只能有一個(gè)線程在被同步化區(qū)域,所以更新共享數(shù)據(jù)時(shí),就像單線程程序在更新數(shù)據(jù)一樣,以保證對(duì)象中的數(shù)據(jù)會(huì)與給定的數(shù)據(jù)同步。

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

    Java代碼?
    1. public ? void ?setNameAndID(String?name,String?id) ??
    2. ??{? //同步某個(gè)程序區(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. }??

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

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

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

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

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

    主站蜘蛛池模板: 亚洲日韩中文字幕无码一区| 无码 免费 国产在线观看91| 日本无卡码免费一区二区三区| 伊人久久国产免费观看视频| 亚洲人成电影亚洲人成9999网| 成熟女人特级毛片www免费| 男女交性无遮挡免费视频| 亚洲欧洲日产国码久在线观看| 成人黄18免费视频| 中文字幕视频免费在线观看| 国产午夜亚洲精品国产| 亚洲乱色熟女一区二区三区丝袜| 免费电视剧在线观看| 中文字幕免费播放| 亚洲精品无码永久在线观看男男 | 一本大道一卡二大卡三卡免费| 亚洲短视频男人的影院| 国产真人无遮挡作爱免费视频| 免费在线看黄的网站| 亚洲AV成人片无码网站| 亚洲一二成人精品区| 亚洲&#228;v永久无码精品天堂久久 | 国产午夜免费高清久久影院| 亚洲国产成人无码AV在线影院| 人人狠狠综合久久亚洲88| 日韩免费电影在线观看| 在线观看免费中文视频| 午夜免费国产体验区免费的| 亚洲最大中文字幕无码网站| 亚洲伊人tv综合网色| 国外亚洲成AV人片在线观看| 午夜毛片不卡高清免费| 1区2区3区产品乱码免费| 精品免费久久久久国产一区| 国产AV无码专区亚洲AV麻豆丫| 亚洲综合综合在线| 亚洲AV本道一区二区三区四区| 亚洲国产一级在线观看| 黄网址在线永久免费观看 | 亚洲一区二区无码偷拍| 亚洲欧洲精品国产区|