隨筆-200  評論-148  文章-15  trackbacks-0

          synchronized的作用?
          一、同步方法
          public synchronized void methodAAA(){

          //….

          }
          鎖定的是調(diào)用這個同步方法的對象

          測試:
          a、不使用這個關(guān)鍵字修飾方法,兩個線程調(diào)用同一個對象的這個方法。
          目標(biāo)類:

          1 public ? class ?TestThread? {
          2 ???? public ?? void ?execute() {?? // synchronized,未修飾
          3 ???????? for ( int ?i = 0 ;i < 100 ;i ++ ) {
          4 ????????????System.out.println(i);
          5 ????????}
          ????
          6 ????}

          7 }


          線程類:

          1 public ? class ?ThreadA? implements ?Runnable {
          2 ????TestThread?test = null ;
          3 ???? public ?ThreadA(TestThread?pTest) {?? // 對象有外部引入,這樣保證是同一個對象
          4 ????????test = pTest;
          5 ????}

          6 ???? public ? void ?run()? {
          7 ????????test.execute();
          8 ????}

          9 }

          調(diào)用:
          1TestThread?test=new?TestThread();
          2Runnable?runabble=new?ThreadA(test);
          3Thread?a=new?Thread(runabble,"A");????????????????
          4a.start();
          5Thread?b=new?Thread(runabble,"B");
          6b.start();


          結(jié)果:
          輸出的數(shù)字交錯在一起。說明不是同步的,兩個方法在不同的線程中是異步調(diào)用的。

          b、修改目標(biāo)類,增加synchronized修飾

          1public?class?TestThread?{
          2????public?synchronized??void?execute(){??//synchronized修飾
          3????????for(int?i=0;i<100;i++){
          4????????????System.out.println(i);
          5????????}
          ????
          6????}

          7}


          結(jié)果:
          輸出的數(shù)字是有序的,首先輸出A的數(shù)字,然后是B,說明是同步的,雖然是不同的線程,但兩個方法是同步調(diào)用的。
          注意:上面雖然是兩個不同的線程,但是是同一個實例對象。下面使用不同的實例對象進(jìn)行測試。

          c、每個線程都有獨立的TestThread對象。
          目標(biāo)類:

          1public?class?TestThread?{
          2????public?synchronized?void?execute(){??//synchronized修飾
          3????????for(int?i=0;i<100;i++){
          4????????????System.out.println(i);
          5????????}
          ????
          6????}

          7}

          線程類:
          1public?class?ThreadA?implements?Runnable{
          2????public?void?run()?{
          3????????TestThread?test=new?TestThread();
          4????????test.execute();
          5????}

          6}

          7

          調(diào)用:
          1Runnable?runabble=new?ThreadA();
          2Thread?a=new?Thread(runabble,"A");????????????????
          3a.start();
          4Thread?b=new?Thread(runabble,"B");
          5b.start();


          結(jié)果:
          輸出的數(shù)字交錯在一起。說明雖然增加了synchronized 關(guān)鍵字來修飾方法,但是不同的線程調(diào)用各自的對象實例,兩個方法仍然是異步的。

          引申:
          對于這種多個實例,要想實現(xiàn)同步即輸出的數(shù)字是有序并且按線程先后順序輸出,我們可以增加一個靜態(tài)變量,對它進(jìn)行加鎖(后面將說明鎖定的對象)。

          修改目標(biāo)類:

          ?1public?class?TestThread?{
          ?2????private?static?Object?lock=new?Object();?//必須是靜態(tài)的。
          ?3????public??void?execute(){
          ?4????????synchronized(lock){
          ?5????????????for(int?i=0;i<100;i++){
          ?6????????????????System.out.println(i);
          ?7????????????}
          ????
          ?8????????}

          ?9????}

          10}

          二、同步代碼塊

          1public?void?method(SomeObject?so){
          2????synchronized(so)
          3???????//…..
          4????}

          5}

          鎖定一個對象,其實鎖定的是該對象的引用(object reference)
          誰拿到這個鎖誰就可以運(yùn)行它所控制的那段代碼。當(dāng)有一個明確的對象作為鎖時,就可以按上面的代碼寫程序,但當(dāng)沒有明確的對象作為鎖,只是想讓一段代碼同步時,可以創(chuàng)建一個特殊的instance變量(它必須是一個對象)來充當(dāng)鎖(上面的解決方法就是增加了一個狀態(tài)鎖)。

          a、鎖定一個對象,它不是靜態(tài)的
          private byte[] lock = new byte[0]; // 特殊的instance變量
          目標(biāo)類:

          ?1public?class?TestThread?{
          ?2????private?Object?lock=new?Object();?
          ?3????public??void?execute(){
          ?4????????synchronized(lock){??//增加了個鎖,鎖定了對象lock,在同一個類實例中,是線程安全的,但不同的實例還是不安全的。
          ?5
          ?6因為不同的實例有不同對象鎖lock
          ?7????????????for(int?i=0;i<100;i++){
          ?8????????????????System.out.println(i);
          ?9????????????}
          ????
          10????????}

          11????}

          12}
          ??


          其實上面鎖定一個方法,等同于下面的:

          1public?void?execute(){??
          2????synchronized(this){???//同步的是當(dāng)然對象
          3????????for(int?i=0;i<100;i++){
          4????????????System.out.println(i);
          5????????}
          ????
          6????}

          7}

          b、鎖定一個對象或方法,它是靜態(tài)的
          這樣鎖定,它鎖定的是對象所屬的類
          public synchronized? static void execute(){
          ??? //...
          }
          等同于

          1public?class?TestThread?{
          2????public?static?void?execute(){
          3????????synchronized(TestThread.class){
          4????????????//
          5????????}

          6????}

          7}

          測試:

          目標(biāo)類:

          ?1public?class?TestThread?{
          ?2????private?static?Object?lock=new?Object();
          ?3????public?synchronized?static?void?execute(){??//同步靜態(tài)方法
          ?4????????for(int?i=0;i<100;i++){
          ?5????????????System.out.println(i);
          ?6????????}
          ????
          ?7????}

          ?8????public?static?void?execute1(){
          ?9????????for(int?i=0;i<100;i++){
          10????????????System.out.println(i);
          11????????}
          ????
          12????}

          13????public?void?test(){
          14????????execute();?????//輸出是有序的,說明是同步的
          15????????//execute1();??//輸出是無須的,說明是異步的
          16????}

          17}

          線程類:調(diào)用不同的方法,于是建立了兩個線程類

          ?1public?class?ThreadA?implements?Runnable{
          ?2????public?void?run()?{
          ?3????????TestThread.execute();//調(diào)用同步靜態(tài)方法
          ?4????}

          ?5}

          ?6public?class?ThreadB?implements?Runnable{
          ?7????public?void?run()?{
          ?8????????TestThread?test=new?TestThread();
          ?9????????test.test();//調(diào)用非同步非靜態(tài)方法
          10????}

          11}

          調(diào)用:

          1Runnable?runabbleA=new?ThreadA();
          2Thread?a=new?Thread(runabbleA,"A");????????????????
          3a.start();
          4Runnable?runabbleB=new?ThreadB();
          5Thread?b=new?Thread(runabbleB,"B");????????????????
          6b.start();

          注意:
          1、用synchronized 來鎖定一個對象的時候,如果這個對象在鎖定代碼段中被修改了,則這個鎖也就消失了。看下面的實例:

          目標(biāo)類:

          ?1public?class?TestThread?{
          ?2?????private?static?final?class?TestThreadHolder?{
          ?3????????????private?static?TestThread?theSingleton?=?new?TestThread();
          ?4????????????public?static?TestThread?getSingleton()?{
          ?5????????????????return?theSingleton;
          ?6????????????}

          ?7????????????private?TestThreadHolder()?{
          ?8????????????}

          ?9????????}

          10?????
          11????private?Vector?ve?=null;
          12????private?Object?lock=new?Object();
          13????private?TestThread(){
          14????????ve=new?Vector();
          15????????initialize();
          16????}

          17????public?static?TestThread?getInstance(){
          18????????return?TestThreadHolder.getSingleton();
          19????}

          20????private?void?initialize(){
          21????????for(int?i=0;i<100;i++){
          22????????????ve.add(String.valueOf(i));
          23????????}

          24????}

          25????public?void?reload(){
          26????????synchronized(lock){
          27????????????ve=null;????????????
          28????????????ve=new?Vector();
          29????????????????????????//lock="abc";?
          30????????????for(int?i=0;i<100;i++){
          31????????????????ve.add(String.valueOf(i));
          32????????????}

          33????????}

          34????????System.out.println("reload?end");
          35????}

          36????
          37????public?boolean?checkValid(String?str){
          38????????synchronized(lock){
          39????????????System.out.println(ve.size());
          40????????????return?ve.contains(str);
          41????????}

          42????}

          43}

          說明:在reload和checkValid方法中都增加了synchronized關(guān)鍵字,對lock對象進(jìn)行加鎖。在不同線程中對同一個對象實例分別調(diào)用reload和checkValid方法。
          在reload方法中,不修改lock對象即注釋lock="abc"; ,結(jié)果在控制臺輸出reload end后才輸出100。說明是同步調(diào)用的。
          如果在reload方法中修改lock對象即去掉注釋,結(jié)果首先輸出了一個數(shù)字(當(dāng)前ve的大小),然后輸出reload end。說明是異步調(diào)用的。

          2、單例模式中對多線程的考慮

          ?1public?class?TestThread?{
          ?2?????private?static?final?class?TestThreadHolder?{
          ?3????????????private?static?TestThread?theSingleton?=?new?TestThread();
          ?4????????????public?static?TestThread?getSingleton()?{
          ?5????????????????return?theSingleton;
          ?6????????????}

          ?7????????????private?TestThreadHolder()?{
          ?8????????????}

          ?9????????}

          10????private?Vector?ve?=null;
          11????private?Object?lock=new?Object();
          12????private?TestThread(){
          13????????ve=new?Vector();
          14????????initialize();
          15????}

          16????public?static?TestThread?getInstance(){
          17????????return?TestThreadHolder.getSingleton();
          18????}

          19????????'''
          20}

          說明:增加了一個內(nèi)部類,在內(nèi)部類中申明一個靜態(tài)的對象,實例化該單例類,初始化的數(shù)據(jù)都在單例類的構(gòu)造函數(shù)中進(jìn)行。這樣保證了多個實例同時訪問的時候,初始化的數(shù)據(jù)都已經(jīng)成功初始化了。

          總結(jié):
          A. 無論synchronized關(guān)鍵字加在方法上還是對象上,它取得的鎖都是對象,而不是把一段代碼或函數(shù)當(dāng)作鎖,所以首先應(yīng)知道需要加鎖的對象
          B.每個對象只有一個鎖(lock)與之相關(guān)聯(lián)。
          C.實現(xiàn)同步是要很大的系統(tǒng)開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制
          posted on 2008-08-06 14:44 無聲 閱讀(427) 評論(0)  編輯  收藏 所屬分類: 職場生活
          道可道非常道,名可名非常名
          <2008年8月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(5)

          我參與的團(tuán)隊

          隨筆分類(174)

          隨筆檔案(200)

          文章分類(20)

          文章檔案(15)

          收藏夾

          開源網(wǎng)站

          朋友博客

          最新隨筆

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 莫力| 辉县市| 正宁县| 铅山县| 林州市| 宝清县| 清远市| 武安市| 岐山县| 呼伦贝尔市| 荣成市| 景宁| 揭阳市| 岚皋县| 石屏县| 尼勒克县| 高邑县| 美姑县| 开平市| 巴塘县| 横峰县| 密山市| 延长县| 上林县| 高阳县| 泽库县| 黎平县| 资溪县| 普陀区| 连州市| 静海县| 罗田县| 曲阜市| 临夏县| 崇礼县| 阿拉善左旗| 会泽县| 洛川县| 文安县| 游戏| 沛县|