bomberlhl

          統計

          留言簿(1)

          閱讀排行榜

          評論排行榜

          【轉】使用synchronized進行Java線程同步

          線程同步指多個線程同時訪問某資源時,采用一系列的機制以保證同時最多只能一個線程訪問該資源。
          為什么需要線程同步呢?
          我們舉一個最簡單的例子來說明為什么需要線程同步。
          比如有一本書(有且只有一本),交給多個售貨員同時去賣;
          如果其中任何一個售貨員把這本書給賣了,其他售貨員就不能再賣這本書了。
          現實生活中,如果要保證該書不會被多個售貨員同時賣掉,必須要有一種機制來保證:
          比如,售貨員應該拿到該書之后才能開始賣書,暫時拿不到的話就只能等該書被退回柜臺。

          售書的完整的例子可以參考 范例解說Java里的線程概念與線程同步技術 一文

          這里,每一個售貨員售書可以看作一個線程。欲售的書便是各線程需要共享的資源。
          開始售書之前,需要取得該書(資源),取不到情況下等待:資源取得
          開始售書之后,則需要取得對該書的獨享控制(不讓他人拿到該書):資源加鎖
          售完書時,需要通知柜臺該書已售出;或者未售出時,把書退回柜臺(通知他人可以拿到該書):資源解鎖

          synchronized控制線程同步的概念跟此完全一樣。
          Java里可以使用synchronized來同步代碼塊或者方法。
          同步代碼塊例:
          1. synchronized(欲同步的對象obj) {
          2.     需要同步的代碼塊   
          3. }  

          可以同步代碼塊。

          synchronized (obj) 表示若多個線程同時訪問時,只讓其中一個線程最先取得obj對象并對其加鎖,其它線程則阻塞直到取得obj對象的線程執行完代碼塊,此時被加鎖的obj對象得到釋放(解鎖),其它線程得到通知取得該book對象繼續執行。
          很多情況下,可以使用synchronized (this){...}來同步代碼塊。但需要注意的是,使用this作為同步對象的話,如果同一個類中存在多個synchronized (this){...}代碼塊,其中任何一個synchronized(this)代碼塊處于被執行狀態,則其它線程對其他synchronized(this)代碼塊的訪問也會受到阻塞。
          為了說明這個問題,我們舉例說明:

          HelloSynchronized.java
          1. publicclass HelloSynchronized {   
          2. publicstaticvoid main(String[] args) {   
          3. //
          4.         HelloSynchronized helloSynchronized = new HelloSynchronized();   
          5. //創建2個線程t1, t2,分別調用HelloSynchronized helloSynchronized的2個方法method1,與method2
          6.         Thread t1 = new Thread(new HelloSynchronizedRunnalbe(helloSynchronized, "method1"), "t1");   
          7.         Thread t2 = new Thread(new HelloSynchronizedRunnalbe(helloSynchronized, "method2"), "t2");   
          8.         t1.start();   
          9.         t2.start();   
          10.     }   
          11. //synchronized public void method1() {    //同步方法
          12. publicvoid method1() {   
          13. synchronized (this) {    //同步塊
          14.             System.out.println(Thread.currentThread().getName()
          15.                     + " enter method1");   
          16. try {
          17.                 Thread.sleep(3000);   
          18.             } catch (InterruptedException e) {
          19. // do nothing
          20.             }   
          21.             System.out.println(Thread.currentThread().getName()
          22.                     + " exit method1");   
          23.         }   
          24.     }   
          25. //synchronized public void method2() {    //同步方法
          26. publicvoid method2() {   
          27. synchronized (this) {    //同步塊
          28.             System.out.println(Thread.currentThread().getName()
          29.                     + " enter method2");   
          30. try {
          31.                 Thread.sleep(3000);   
          32.             } catch (InterruptedException e) {
          33. // do nothing
          34.             }   
          35.             System.out.println(Thread.currentThread().getName()
          36.                     + " exit method2");   
          37.         }   
          38.     }   
          39. }   
          40. class HelloSynchronizedRunnalbe implements Runnable {   
          41. private HelloSynchronized helloSynchronized;
          42. private String methodName;   
          43. public HelloSynchronizedRunnalbe(HelloSynchronized helloSynchronized, String methodName) {
          44. this.helloSynchronized = helloSynchronized;
          45. this.methodName = methodName;   
          46.     }   
          47. publicvoid run() {   
          48. if (methodName.equals("method1")) {   
          49.             helloSynchronized.method1();   
          50.         } elseif (methodName.equals("method2")) {   
          51.             helloSynchronized.method2();   
          52.         }   
          53.     }   
          54. }  


          運行結果為:
          t1 enter method1
          t1 exit method1
          t2 enter method2
          t2 exit method2
          等到線程t1結束后,t2才開始運行(t2受到阻塞)

          再把synchronized (this)去掉,運行結果為:
          t1 enter method1
          t2 enter method2
          t1 exit method1
          t2 exit method2
          線程t1,t2同時運行

          同步方法例:
          1. synchronizedprivatevoid sellBook(Book book) {   
          2. ...   
          3. }  

          這種方法其實相當于
          1. privatevoid sellBook(Book book) {   
          2. synchronized(this) {   
          3.         ...   
          4.     }   
          5. }  

          由于默認采用this作為同步對象,所以當一個類中有多個synchronized方法時,同樣會存在以上問題:即如果有一個線程訪問其中某個synchronized方法時,直到該方法執行完畢,其它線程對其它synchronized方法的訪問也將受到阻塞。
          大家可以把上面的例子稍加改造,去掉代碼中的synchronized (this),改為synchronized public void method1(),synchronized public void method2()同步形式,運行后會得到同樣結果。

          多同步代碼塊synchronized(this){...}的多線程阻塞問題(包括synchronized同步方法),在并發處理的系統中(比如WEB服務器)會嚴重影響性能,建議慎重使用。可以使用synchronized(obj){...}縮小同步資源對象的范圍來解決這個問題。

          posted on 2009-12-14 19:33 異域流浪 閱讀(288) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 华宁县| 扎兰屯市| 大关县| 光山县| 临夏县| 巴楚县| 保亭| 尤溪县| 罗田县| 耿马| 富顺县| 兴海县| 军事| 邢台县| 南康市| 宣城市| 洪泽县| 泊头市| 灌南县| 临江市| 驻马店市| 平江县| 靖安县| 故城县| 昭觉县| 夏津县| 奇台县| 宽城| 荆门市| 锡林浩特市| 望都县| 石阡县| 历史| 远安县| 安岳县| 任丘市| 松原市| 天台县| 威海市| 宁阳县| 佛山市|