1. 程式人生 > >java鎖學習(二)

java鎖學習(二)

類鎖

類鎖 !!!! java類有很多物件 ,但是隻有一個class物件 !!!!

所以,類鎖,就是針對當前類的Class物件的鎖

類鎖同一時刻只能被一個物件獲取

  1. synchronized放在static方法上(靜態鎖)
  2. synchronized放在class物件上

靜態鎖

class SyncClassStatic implements Runnable {
    @Override
    public void run() {
        method();
    }

    public static synchronized void method() {
        System.out.println("我是類鎖中靜態鎖");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"執行結束");
    }
}
result:
我是類鎖中靜態鎖
Thread-6執行結束
我是類鎖中靜態鎖
Thread-7執行結束
類鎖,靜態鎖執行完畢

class物件鎖

class SyncClassObj implements Runnable{
    @Override
    public void run() {
        method();
    }

    private void method(){
        synchronized (SyncClassObj.class) {
            System.out.println("我是類鎖中class物件鎖");
            try{
                Thread.sleep(3000);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"執行結束");
        }
    }
}
result:
我是類鎖中class物件鎖
Thread-8執行結束
我是類鎖中class物件鎖
Thread-9執行結束
類鎖,class物件執行完畢

常見場景和問題

  1. 兩個執行緒同時訪問一個物件的同步方法會怎樣?

    依次執行(鎖住的是同一個物件)

  2. 兩個執行緒訪問的是兩個物件的同步方法又會怎樣?

    隨機執行(鎖住的是不同的物件)

  3. 兩個執行緒訪問的是synchronized的靜態方法會怎樣?

    依次執行(鎖住的是同一個類)

  4. 同時訪問同步方法與非同步方法會怎樣?

    只鎖加了synchronized的方法,其他方法不會收到影響

class SyncObjLock implements Runnable {


    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")) {
            syncMethod();
        }else{
            asyncMethod();
        }
    }

    private synchronized void syncMethod()
    {
        System.out.println("我被鎖了");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"執行結束");
    }

    private void asyncMethod()
    {
        System.out.println("我沒被鎖");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"執行結束");
    }
}
同時開始,同時結束:
我被鎖了
我沒被鎖
Thread-0執行結束
Thread-1執行結束
  1. 訪問同一個物件的不同的普通同步方法會怎樣?
class SyncDiff implements Runnable{
    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")) {
            syncMethod1();
        }else{
            syncMethod2();
        }
    }


    private synchronized void syncMethod1()
    {
        System.out.println("我被鎖了,我是方法1");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"執行結束");
    }


    private synchronized void syncMethod2()
    {
        System.out.println("我被鎖了,我是方法2");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"執行結束");
    }
}
同時開始,同時結束:
我被鎖了
我沒被鎖
Thread-0執行結束
Thread-1執行結束
  1. 同時訪問靜態sync和非靜態sync方法
class SyncStaticOrNo implements Runnable {
    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")) {
            syncMethod1();
        }else{
            syncMethod2();
        }
    }


    private synchronized void syncMethod1()
    {
        System.out.println("我被物件鎖");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"執行結束");
    }


    private static synchronized void syncMethod2()
    {
        System.out.println("我是類鎖");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+"執行結束");
    }
}
同時開始,同時結束:
我被鎖了
我沒被鎖
Thread-0執行結束
Thread-1執行結束
  1. 方法丟擲異常後,會釋放鎖嗎?

會,jvm幫我們釋放了

class SyncExc implements Runnable{


    @Override
    public void run() {
            method1();
    }

    private synchronized void method1()
    {
        System.out.println(Thread.currentThread().getName()+"開始");
        try{
            Thread.sleep(3000);
        }catch (Exception e) {
            e.printStackTrace();
        }
        throw new RuntimeException("");
//        System.out.println("執行結束");
    }

}
Thread-0開始
Exception in thread "Thread-0" java.lang.RuntimeException: 
	at Thread.SyncExc.method1(SynchronizedObject.java:187)
	at Thread.SyncExc.run(SynchronizedObject.java:176)
	at java.lang.Thread.run(Thread.java:748)
Thread-1開始
Exception in thread "Thread-1" java.lang.RuntimeException: 
	at Thread.SyncExc.method1(SynchronizedObject.java:187)
	at Thread.SyncExc.run(SynchronizedObject.java:176)
	at java.lang.Thread.run(Thread.java:748)

鎖的使用場景及分析

整個系統全域性同步用類鎖,區域性鎖用物件鎖

對比下,就像一樣,鎖的範圍越大,效能自然越低(粒度:類鎖>物件鎖 效能