<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)的

    主站蜘蛛池模板: 亚洲人成网77777亚洲色 | 亚洲国产一区视频| 中国极品美軳免费观看| 亚洲综合色一区二区三区小说| 午夜dj在线观看免费视频| 久香草视频在线观看免费| 亚洲精品中文字幕乱码| 日本特黄特色aa大片免费| 久久久久久噜噜精品免费直播| 亚洲人6666成人观看| 亚洲成片观看四虎永久| 曰批全过程免费视频播放网站| 免费无遮挡无码视频在线观看| 亚洲天堂视频在线观看| 国产免费爽爽视频免费可以看| 免费91最新地址永久入口| 亚洲AV无码成人精品区狼人影院 | 亚洲激情校园春色| 亚洲阿v天堂在线2017免费| 久久精品毛片免费观看| 特色特黄a毛片高清免费观看| 亚洲国产高清在线精品一区| 久久亚洲中文字幕精品一区| 夫妻免费无码V看片| 人妻无码一区二区三区免费 | 猫咪免费观看人成网站在线| 亚洲大香伊人蕉在人依线| 久久亚洲色一区二区三区| 免费看a级黄色片| 6080午夜一级毛片免费看| 国产国产人免费人成成免视频| 77777午夜亚洲| 亚洲精品国产成人专区| 亚洲中文字幕无码一区二区三区| 永久在线毛片免费观看| 四虎永久在线观看免费网站网址| 免费一区二区无码东京热| 一级做性色a爰片久久毛片免费| 亚洲中文字幕久久精品蜜桃| 久久国产亚洲精品无码| 亚洲va无码手机在线电影|