通過幾個例子,進一步理解Java的Synchronized鎖中對象鎖與類鎖

資源類:電話,有發短信與打電話的功能。

class Phone
{

    public void send() throws InterruptedException 
    {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("發短信");
    }

    public void call()
    {
        System.out.println("打電話");
    }

}

1、電話類中的方法都用synchronized修飾,並且只實例化一個對象Phone phone = new Phone();,此時線程拿到的鎖是phone的對象鎖,每個對象有一把鎖,多個線程使用同一個對象,多個線程就是使用一把鎖,先調用的先執行!

package juc;

import java.util.concurrent.TimeUnit;

/**
 * @program: relearn
 * @description:
 * @author: qinda
 * @create: 2020-05-09 12:36
 **/
public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{
            try {
                phone.send();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
            phone.call();
        },"B").start();
    }
}

class Phone{

    public synchronized void send() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("發短信");
    }

    public synchronized void call()
    {
        System.out.println("打電話");
    }

}
//發短信
//打電話

2、現在在Phone中新增方法public void hello(),不使用synchronized修飾,此時如果有線程調用hello方法,將不會考慮鎖的問題,也不會阻塞,因爲這個方法並不是同步方法。多個線程,有的線程有鎖,有的線程沒鎖,兩者之間不存在競爭同一把鎖的情況,先後執行順序是隨機的。


package juc;

import java.util.concurrent.TimeUnit;

/**
 * @program: relearn
 * @description:
 * @author: qinda
 * @create: 2020-05-09 12:36
 **/
public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{
            try {
                phone.send();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
            phone.call();
        },"B").start();

        new Thread(()->{
            phone.hello();
        },"C").start();
    }
}

class Phone{

    public synchronized void send() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("發短信");
    }

    public synchronized void call()
    {
        System.out.println("打電話");
    }

    public void hello()
    {
        System.out.println("hello");
    }
}
//hello
//發短信
//打電話

3、現在聲明兩個Phone對象
Phone phone = new Phone();
Phone phone2 = new Phone();

因爲每個對象都有一把鎖,所以兩個線程競爭的不是同一把鎖,所以不存在競爭關係
①被 synchronized 修飾的方法,鎖的對象是方法的調用者;

②調用者不同,它們之間用的不是同一個鎖,相互之間沒有關係。

public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();


        new Thread(()->{
            try {
                phone.send();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
            phone2.call();
        },"B").start();

    }
}

class Phone{

    public synchronized void send() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("發短信");
    }

    public synchronized void call()
    {
        System.out.println("打電話");
    }
}
//打電話
//發短信

4、現在將兩個方法都加上static修飾被 synchronized 和 static 同時修飾的方法,鎖的對象是類的 class 對象,是唯一的一把鎖。線程之間是順序執行。

鎖Class和鎖對象的區別:

1、Class 鎖 ,類模版,只有一個;

2、對象鎖 , 通過類模板可以new 多個對象。

如果全部都鎖了Class,那麼這個類下的所有對象都具有同一把鎖。

package juc;

import java.util.concurrent.TimeUnit;

/**
 * @program: relearn
 * @description:
 * @author: qinda
 * @create: 2020-05-09 12:36
 **/
public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();


        new Thread(()->{
            try {
                phone.send();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
            phone.call();
        },"B").start();

    }
}

class Phone{

    public static synchronized void send() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("發短信");
    }

    public static synchronized void call()
    {
        System.out.println("打電話");
    }
}
//發短信
//打電話

五、被 synchronized 修飾 和 static 修飾的方法,鎖的對象是類的 class 對象,是唯一的一把鎖。

Class鎖是唯一的,所以多個對象使用的也是同一個Class鎖。

package juc;

import java.util.concurrent.TimeUnit;

/**
 * @program: relearn
 * @description:
 * @author: qinda
 * @create: 2020-05-09 12:36
 **/
public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone1 = new Phone();


        new Thread(()->{
            try {
                phone.send();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
            phone1.call();
        },"B").start();

    }
}

class Phone{

    public static synchronized void send() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("發短信");
    }

    public static synchronized void call()
    {
        System.out.println("打電話");
    }
}
//發短信
//打電話


六、被 synchronized和static修飾的方法,鎖的對象是類的class對象!唯一的同一把鎖;

只被synchronized修飾的方法,是普通鎖(如對象鎖),不是Class鎖,所以進程之間執行順序互不干擾。


package juc;

import java.util.concurrent.TimeUnit;

/**
 * @program: relearn
 * @description:
 * @author: qinda
 * @create: 2020-05-09 12:36
 **/
public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();


        new Thread(()->{
            try {
                phone.send();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
            phone.call();
        },"B").start();

    }
}

class Phone{

    public static synchronized void send() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("發短信");
    }

    public synchronized void call()
    {
        System.out.println("打電話");
    }
}
//打電話
//發短信
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章