synchronized(this/.class/Object),synchronize方法區(qū)別

synchronized關(guān)鍵字的使用

  • 在日常開(kāi)發(fā)中我們經(jīng)??吹絪ynchronized關(guān)鍵字,常見(jiàn)的幾種應(yīng)用是synchronized(this)、synchronized(class)與synchronized(Object),和synchronize方法,靜態(tài)同步synchronized方法,這幾種方式究竟有什么區(qū)別呢,當(dāng)初學(xué)習(xí)java同步鎖那塊的時(shí)候好像就沒(méi)怎么注意過(guò),現(xiàn)在來(lái)通過(guò)實(shí)例比較下:
  • 對(duì)于synchronized(this):

      //核心業(yè)務(wù)代碼
      public class HotProductService {
          public void serviceMethodA(){//業(yè)務(wù)A
              try {
                  synchronized (this) {
                      Log.d("HotProductService","A begin time="+System.currentTimeMillis());
                      Thread.sleep(2000);
                      Log.d("HotProductService","A end   time="+System.currentTimeMillis());
                  }
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
          public void serviceMethodB(){
              synchronized (this) {
                  Log.d("HotProductService","B begin time="+System.currentTimeMillis());
                  Log.d("HotProductService","B end   time="+System.currentTimeMillis());
              }
          }
      }
    
      //線程1
      public class ThreadA extends Thread{
          private HotProductService objectService;
          public ThreadA(HotProductService objectService){
              super();
              this.objectService=objectService;
          }
          @Override
          public void run() {
              super.run();//調(diào)用業(yè)務(wù)a
              objectService.serviceMethodA();
          }
      }
      //線程2
      public class ThreadB extends Thread {
          private HotProductService objectService;
          public ThreadB(HotProductService objectService){
              super();
              this.objectService=objectService;
          }
          @Override
          public void run() {
              super.run();//調(diào)用業(yè)務(wù)b
              objectService.serviceMethodB();
          }
      }
      //測(cè)試代碼
      private void test1() {
              HotProductService service=new HotProductService();
              ThreadA a=new ThreadA(service);
              a.start();
              ThreadB b=new ThreadB(service);
              b.start();
          }
    

運(yùn)行結(jié)果:

    02-24 10:05:12.135 6434-7477/com.example.refreshdemo D/HotProductService: A begin time=1519437912141
    02-24 10:05:14.135 6434-7477/com.example.refreshdemo D/HotProductService: A end   time=1519437914142
    02-24 10:05:14.135 6434-7478/com.example.refreshdemo D/HotProductService: B begin time=1519437914145
    02-24 10:05:14.135 6434-7478/com.example.refreshdemo D/HotProductService: B end   time=1519437914146

上面的結(jié)果我們能看到即使A業(yè)務(wù)耗時(shí)較長(zhǎng),B業(yè)務(wù)也并不會(huì)獲得執(zhí)行的機(jī)會(huì),如果我們將核心業(yè)務(wù)代碼中B業(yè)務(wù)或者A業(yè)務(wù)的同步鎖去掉,其他照舊會(huì)是怎么樣

    ...
    比如去掉B業(yè)務(wù)的同步鎖
    public void serviceMethodB(){
    //synchronized (this) 
        {
        Log.d("HotProductService","B begin time="+System.currentTimeMillis());
        Log.d("HotProductService","B end   time="+System.currentTimeMillis());
        }
    }
    ...

運(yùn)行結(jié)果:

    02-24 02:27:19.248 3562-3629/com.example.refreshdemo D/HotProductService: A begin time=1519439239248
    02-24 02:27:19.248 3562-3630/com.example.refreshdemo D/HotProductService: B begin time=1519439239248
    02-24 02:27:19.248 3562-3630/com.example.refreshdemo D/HotProductService: B end   time=1519439239248
    02-24 02:27:21.248 3562-3629/com.example.refreshdemo D/HotProductService: A end   time=1519439241248

結(jié)論:synchronized (this)使用的對(duì)象監(jiān)視器是一個(gè),即是該對(duì)象自身,當(dāng)一個(gè)線程訪問(wèn)HotProductService的一個(gè)synchronized (this)同步代碼塊時(shí),其它線程對(duì)同一個(gè)HotProductService中其它的synchronized (this)同步代碼塊的訪問(wèn)將是堵塞,實(shí)現(xiàn)了代碼順序的同步執(zhí)行。

  • 對(duì)于synchronized修飾的方法:
    上面的結(jié)論對(duì)于synchronized修飾的方法是否同樣有效呢,通過(guò)實(shí)例看下:

      //核心業(yè)務(wù)代碼
      public class HotProductService {
          //業(yè)務(wù)A
          public synchronized void objectMethodA(){
              Log.d("HotProductService","run----objectMethodA2");
          }
          //業(yè)務(wù)B
          public void objectMethodB(){
              synchronized (this) {
                  try {
                      for (int i = 1; i <= 10; i++) {
                          Log.d("HotProductService","synchronized thread name:"+Thread.currentThread().getName()+"-->i="+i);
                          Thread.sleep(1000);
                      }
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      
      //A線程
      public class ThreadA2 extends Thread{
          private HotProductService objectService;
          public ThreadA2(HotProductService objectService){
              super();
              this.objectService=objectService;
          }
          @Override
          public void run() {
              super.run();
              objectService.objectMethodA();
          }
      }
    
      //B線程
      public class ThreadB2 extends Thread {
          private HotProductService objectService;
          public ThreadB2(HotProductService objectService){
              super();
              this.objectService=objectService;
          }
          @Override
          public void run() {
              super.run();
              objectService.objectMethodB();
          }
      }
      
      private void test2() {
              HotProductService service=new HotProductService();
              ThreadA2 a=new ThreadA2(service);
              a.start();
              ThreadB2 b=new ThreadB2(service);
              b.start();
          }
    

運(yùn)行結(jié)果:

    02-24 02:48:32.212 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=1
    02-24 02:48:33.213 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=2
    02-24 02:48:34.214 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=3
    02-24 02:48:35.215 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=4
    02-24 02:48:36.216 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=5
    02-24 02:48:37.217 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=6
    02-24 02:48:38.218 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=7
    02-24 02:48:39.219 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=8
    02-24 02:48:40.220 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=9
    02-24 02:48:41.221 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=10
    02-24 02:48:42.223 3562-3764/com.example.refreshdemo D/HotProductService: run----objectMethodA2

同樣驗(yàn)證了只能同時(shí)被一個(gè)線程所訪問(wèn)synchronized代碼塊。其他線程遇到synchronized代碼塊將會(huì)堵塞。

  • 那么synchronized(Object)呢

      //核心業(yè)務(wù)代碼
          public class HotProductService {
              private String uname;
              private String pwd;
              String lock=new String();
              public void setUserNamePassWord(String userName,String passWord){
                  try {
                      synchronized (lock) {
                          Log.d("HotProductService","thread name=" + Thread.currentThread().getName()
                                  + " 進(jìn)入代碼快:" + System.currentTimeMillis());
                          uname=userName;
                          Thread.sleep(3000);
                          pwd=passWord;
                          Log.d("HotProductService","thread name="+Thread.currentThread().getName()
                                  +" 進(jìn)入代碼快:"+System.currentTimeMillis()+"入?yún)name:"+uname+"入?yún)wd:"+pwd);
                      }
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
    
      //A線程
      public class ThreadA3 extends Thread{
          private HotProductService objectService;
          public ThreadA3(HotProductService objectService){
              super();
              this.objectService=objectService;
          }
          @Override
          public void run() {
              super.run();
              objectService.setUserNamePassWord("a","aa");
          }
      }
    
      //B線程
      public class ThreadB3 extends Thread {
          private HotProductService objectService;
          public ThreadB3(HotProductService objectService){
              super();
              this.objectService=objectService;
          }
          @Override
          public void run() {
              super.run();
              objectService.setUserNamePassWord("b","bb");
          }
      }
    
      HotProductService service=new HotProductService();
      ThreadA2 a=new ThreadA2(service);
      a.start();
      ThreadB2 b=new ThreadB2(service);
      b.start();
    

運(yùn)行結(jié)果:

    02-24 02:57:41.380 3975-4016/? D/HotProductService: thread name=A 進(jìn)入代碼快:1519441061380
    02-24 02:57:44.382 3975-4016/com.example.refreshdemo D/HotProductService: thread name=A 進(jìn)入代碼快:1519441064382入?yún)name:a入?yún)wd:aa
    02-24 02:57:44.382 3975-4017/com.example.refreshdemo D/HotProductService: thread name=B 進(jìn)入代碼快:1519441064382
    02-24 02:57:47.383 3975-4017/com.example.refreshdemo D/HotProductService: thread name=B 進(jìn)入代碼快:1519441067383入?yún)name:b入?yún)wd:bb

如果我們將

    //核心業(yè)務(wù)代碼
        public class HotProductService {
            private String uname;
            private String pwd;
           //String lock=new String();移入方法會(huì)得到什么樣的結(jié)果呢
            public void setUserNamePassWord(String userName,String passWord){
                try {
                    String lock=new String();
                    synchronized (lock) {
                        Log.d("HotProductService","thread name=" + Thread.currentThread().getName()
                                + " 進(jìn)入代碼快:" + System.currentTimeMillis());
                        uname=userName;
                        Thread.sleep(3000);
                        pwd=passWord;
                        Log.d("HotProductService","thread name="+Thread.currentThread().getName()
                                +" 進(jìn)入代碼快:"+System.currentTimeMillis()+"入?yún)name:"+uname+"入?yún)wd:"+pwd);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

其他代碼照舊得到
運(yùn)行結(jié)果:

    02-24 03:04:16.757 4148-4187/? D/HotProductService: thread name=A 進(jìn)入代碼快:1519441456757
    02-24 03:04:16.758 4148-4188/? D/HotProductService: thread name=B 進(jìn)入代碼快:1519441456758
    02-24 03:04:19.758 4148-4187/com.example.refreshdemo D/HotProductService: thread name=A 進(jìn)入代碼快:1519441459758入?yún)name:b入?yún)wd:aa
    02-24 03:04:19.759 4148-4188/com.example.refreshdemo D/HotProductService: thread name=B 進(jìn)入代碼快:1519441459759入?yún)name:b入?yún)wd:bb

是不是很奇怪出錯(cuò)了?為什么呢 移入方法內(nèi)部就不對(duì)了,比較前后改變,發(fā)現(xiàn)修改后每次調(diào)用方法時(shí)(哪個(gè)線程調(diào)用方法時(shí))都會(huì)重新new一個(gè)對(duì)象作為對(duì)象鎖,但是修改前不管哪次進(jìn)入方法時(shí)(哪個(gè)線程調(diào)用方法時(shí))用的都是同一個(gè)對(duì)象,所以我們得到結(jié)論:

使用自定義任意對(duì)象進(jìn)行同步鎖 不同線程必須為同一對(duì)象,否則仍舊是異步運(yùn)行的

  • synchronized(.class)與靜態(tài)同步synchronized方法

可以直接給出的結(jié)論是這兩種方式的同步是一樣的,使用的同步鎖都是對(duì)應(yīng)的類(lèi)作為對(duì)象鎖,在jvm中類(lèi)是唯一的,那也就是說(shuō)對(duì)任何對(duì)象都是同步的,因?yàn)榫哂形ㄒ坏膶?duì)象鎖。下面來(lái)驗(yàn)證下:

    //核心業(yè)務(wù)代碼
    public class HotProductService {
        //業(yè)務(wù)A
        public  void methodA(){
            try {
                synchronized (HotProductService.class){
                    Log.d("HotProductService","static methodA begin Name:" + Thread.currentThread().getName() + " times:" + System.currentTimeMillis());
                    Thread.sleep(2000);
                    Log.d("HotProductService","static methodA end   Name:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //業(yè)務(wù)B
        public  void methodB(){
            synchronized (HotProductService.class){
                Log.d("HotProductService","static methodB begin Name:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
                Log.d("HotProductService","static methodB end   Name:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
            }
        }
    }

    //A線程
    public class ThreadA5 extends Thread{
    
        private  HotProductService mHotProductService;
    
        public ThreadA5(HotProductService hotProductService){
            mHotProductService = hotProductService;
        }
        @Override
        public void run() {
            super.run();
            mHotProductService.methodA();
        }
    }
    
    //B線程
    public class ThreadB5 extends Thread {
    
        private  HotProductService mHotProductService;
    
        public ThreadB5(HotProductService hotProductService){
            mHotProductService = hotProductService;
        }
        @Override
        public void run() {
            super.run();
            mHotProductService.methodB();
        }
    }

    private void test5() {
        HotProductService service= new HotProductService();
        ThreadA5 a=new ThreadA5(service);
        a.start();
        ThreadB5 b=new ThreadB5(service);
        b.start();
    }

運(yùn)行結(jié)果:

    02-24 03:24:11.250 4148-4282/com.example.refreshdemo D/HotProductService: static methodA begin Name:Thread-174 times:1519442651250
    02-24 03:24:13.252 4148-4282/com.example.refreshdemo D/HotProductService: static methodA end   Name:Thread-174 times:1519442653252
    02-24 03:24:13.252 4148-4283/com.example.refreshdemo D/HotProductService: static methodB begin Name:Thread-175 times:1519442653252
    02-24 03:24:13.252 4148-4283/com.example.refreshdemo D/HotProductService: static methodB end   Name:Thread-175 times:1519442653252

使用.class作為對(duì)象鎖保證了不能線程的同步。
引用網(wǎng)上常見(jiàn)的說(shuō)法就是:

synchronize修飾的方法和 synchronize(this) 都是鎖住自己本身的對(duì)象 而synchronize(class) synchronize(object) 都是鎖別的對(duì)象

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,745評(píng)論 18 399
  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽(yáng)閱讀 2,600評(píng)論 1 15
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類(lèi) 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,112評(píng)論 1 18
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,654評(píng)論 19 139
  • 今年的教師節(jié)和往年一樣,畢業(yè)之后就和我們沒(méi)啥太多關(guān)系,突然一位來(lái)自新疆老同學(xué)的電話,一寒暄在武漢呢,啥也別說(shuō)...
    凡提閱讀 457評(píng)論 0 1

友情鏈接更多精彩內(nèi)容