Synchronized方法鎖、對象鎖、類鎖區別


synchronized關鍵字,我們一般稱之為”同步鎖“,用它來修飾需要同步的方法和需要同步代碼塊,默認是當前對象作為鎖的對象。在修飾類時(或者修飾靜態方法),默認是當前類的Class對象作為所的對象故存在着方法鎖、對象鎖、類鎖 這樣的概念

一.Synchronized方法鎖(也叫對象鎖)

1.修飾在方法上,多個線程調用同一個對象的同步方法會阻塞,調用不同對象的同步方法不會阻塞。(java對象的內存地址是否相同)

 public synchronized void obj3() {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
   }

2.修飾代碼塊,這個this就是指當前對象(類的實例),多個線程調用同一個對象的同步方法會阻塞,調用不同對象的同步方法不會阻塞。(java對象的內存地址是否相同)

public void obj2() {
       synchronized (this) {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
       }
   }

3.修飾代碼塊,這個str就是指String對象,多個線程調用同一個對象的同步方法會阻塞,調用不同對象的同步方法不會阻塞。(java對象的內存地址是否相同)

 public void obj2() {
       String str=new String("lock");//在方法體內,調用一次就實例化一次,多線程訪問不會阻塞,因為不是同一個對象,鎖是不同的
       synchronized (str) {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
       }
   }
public static void main(String[] args) throws InterruptedException {
        test test=new test();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.obj2();
            }
        }).start();
    
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.obj2();
            }
        }).start();
    }
//兩個方法之間交替執行 沒有阻塞
Thread-0 : 4
Thread-1 : 4
Thread-1 : 3
Thread-0 : 3
Thread-1 : 2
Thread-0 : 2
Thread-1 : 1
Thread-0 : 1
Thread-0 : 0
Thread-1 : 0

共用一個對象,多線程調用obj2同步方法,因為使用的是一個對象鎖,會阻塞。

String str=new String("lock"); //對象放在方法外,調用方法的時候不會新創建一個對象。
   public void obj2() {
       synchronized (str) {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
       }
   }

Thread-0 : 4
Thread-0 : 3
Thread-0 : 2
Thread-0 : 1
Thread-0 : 0
Thread-1 : 4
Thread-1 : 3
Thread-1 : 2
Thread-1 : 1
Thread-1 : 0

二.Synchronized類鎖

1.Synchronized修飾靜態的方法

  public static synchronized void obj3() {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
   }

2.synchronized (test.class) ,鎖的對象是test.class,即test類的鎖。

  public void obj1() {
        synchronized (test.class) {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
       }
   }

看完上面的例子,應該可以分清楚什么是對象鎖和類鎖了。

那么問題來了:在一個類中有兩方法,分別用synchronized 修飾的靜態方法(類鎖)和非靜態方法(對象鎖)。多線程訪問兩個方法的時候,線程會不會阻塞?

 public static synchronized void obj3() {
           int i = 5;
           while (i-- > 0) {
               System.out.println(Thread.currentThread().getName() + " : " + i);
               try {
                   Thread.sleep(500);
               } catch (InterruptedException ie) {
               }
           }
   }

 public synchronized void obj4() {
       int i = 5;
       while (i-- > 0) {
           System.out.println(Thread.currentThread().getName() + " : " + i);
           try {
               Thread.sleep(500);
           } catch (InterruptedException ie) {
           }
       }
   }

答案是???

Thread-0 : 4
Thread-1 : 4
Thread-0 : 3
Thread-1 : 3
Thread-1 : 2
Thread-0 : 2
Thread-1 : 1
Thread-0 : 1
Thread-1 : 0
Thread-0 : 0

不會阻塞。

總結 

到這么我們應該知道了:

1,要滿足方法同步(或者代碼塊同步)就必須保證多線程訪問的是同一個對象(在java內存中的地址是否相同)。

2,類鎖和對象鎖同時存在時,多線程訪問時不會阻塞,因為他們不是一個鎖。

----------------------------------------------------------------------------------------------------------------

理解不到位的地方,煩請指出來。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM