8鎖現象

1

標準訪問,先打印郵件還是先發送短信

   解釋 :這個是不能確定的,線程的調度與cpu有關,所以不能確定。但是在代碼中添加了sleep().是爲了讓A線程一定在B線程之前執行,這只是爲了更好的解釋鎖。

class Phone//Phone.java ---> Phone.class    Class.forName()
{
    public synchronized void sendEmail() throws Exception{
        //TimeUnit.SECONDS.sleep(3);//新的寫法
        //Thread.sleep(4000);//暫停4秒鐘
        System.out.println("發郵件");
    }

    public synchronized void sendMessage() throws Exception{
        System.out.println("發短信");
    }
}



    public static void main(String[] args) {
        Phone phone = new Phone();

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

        Thread.sleep( 100 );//這是故意讓A在B前面執行

        new Thread( ()->{
            try {
                phone.sendMessage();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();
    }



標準訪問,請問先打印郵件還是短信(線程調度,不一定) 郵件
 一個對象裏面如果有多個synchronized方法,某一個時刻內,只要有一個線程去調用其中的一個synchronized方法了,
其他的線程都只能等待,換句話說,某一個時刻內,只能有唯一一個線程去訪問這些synchronized方法
    

 

在郵件方法暫停3秒鐘,請問先打印郵件還是短信  答案: 郵件

解釋:鎖的對象是當前對象this,被鎖定後,其他的線程都不能進入到當前對象的其它synchronized方法

class Phone//Phone.java ---> Phone.class    Class.forName()
{
    public synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(3);//新的寫法
        //Thread.sleep(4000);//暫停4秒鐘
        System.out.println("發郵件");
    }

    public synchronized void sendMessage() throws Exception{
        System.out.println("發短信");
    }
}


    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread( ()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();

        Thread.sleep( 100 );//這是故意讓A在B前面執行

        new Thread( ()->{
            try {
                phone.sendMessage();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();
    }


//注意,在發郵件代碼中,讓其暫停3秒是爲了驗證,看其他線程能否訪問當前被synchronize鎖定的對象

在郵件方法暫停4秒鐘,請問先打印郵件還是短信   郵件
鎖的對象是當前對象this,被鎖定後,其他的線程都不能進入到當前對象的其它synchronized方法

 

新增普通的sayHello方法,請問先打印郵件還是sayHello   答案:sayHello(因爲先打印郵件,在裏面等待了3秒。)

解釋:加一個普通方法和同步鎖無關

    public synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(3);//新的寫法
        //Thread.sleep(4000);//暫停4秒鐘
        System.out.println("發郵件");
    }

    public synchronized void sendMessage() throws Exception{
        System.out.println("發短信");
    }

    public synchronized void sayHello() throws Exception{
        System.out.println("Hello");
    }



    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread( ()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();

        Thread.sleep( 100 );//這是故意讓A在B前面執行

        new Thread( ()->{
            try {
                phone.sayHello();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();
    }

 

4

兩部手機,請問先打印郵件還是短信 答案:短信。(只是因爲打印郵件等待了3秒)

解釋:換成兩個對象後,不是同一把鎖了,情況立刻變化

class Phone//Phone.java ---> Phone.class    Class.forName()
{
    public synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(3);//新的寫法
        //Thread.sleep(4000);//暫停4秒鐘
        System.out.println("發郵件");
    }

    public synchronized void sendMessage() throws Exception{
        System.out.println("發短信");
    }
}


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

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

        Thread.sleep( 100 );//這是故意讓A在B前面執行

        new Thread( ()->{
            try {
                phone2.sendMessage();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();
    }

 

5

兩個靜態同步方法,同一部手機,請問先打印郵件還是短信 答案 :郵件

解釋 :

static 鎖的是全局鎖

//Phone.java ---> Phone.class Class.forName() static 鎖的是Class(字節碼文件),但是不影響實例對象,

class Phone//Phone.java ---> Phone.class    Class.forName()
{
    public static synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(3);//新的寫法
        //Thread.sleep(4000);//暫停3秒鐘
        System.out.println("發郵件");
    }

    public static synchronized void sendMessage() throws Exception{
        System.out.println("發短信");
    }
}



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

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

        Thread.sleep( 100 );//這是故意讓A在B前面執行

        new Thread( ()->{
            try {
                phone.sendMessage();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();
    }
/*

 * 5 兩個靜態同步方法,同一部手機,請問先打印郵件還是短信 郵件
 *           static 鎖的是全局鎖
 *           //Phone.java ---> Phone.class    Class.forName() static 鎖的是Class
 *           synchronized實現同步的基礎:Java中的每一個對象都可以作爲鎖
 *                具體表現爲以下3中形式。
 *                    對於普通不同方法,鎖的是當前實例對象。
 *                    對於同步方法塊,鎖是Synchronized括號裏面配置的對象this
 *                    對於靜態同步方法,鎖是當前類的Class對象(模板  不管多少個對象,都是來源於這個鎖 )
 */

 

兩個靜態同步方法,兩部手機看,請問先打印郵件還是短信  答案:郵件

解釋:和第五點幾乎一樣。

因爲第一步手機對象,已經鎖住字節碼,第二個對象必須等着。所以還是第一個手機對象先。。

class Phone//Phone.java ---> Phone.class    Class.forName()
{
    public static synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(3);//新的寫法
        //Thread.sleep(4000);//暫停3秒鐘
        System.out.println("發郵件");
    }

    public static synchronized void sendMessage() throws Exception{
        System.out.println("發短信");
    }
}


    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread( ()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();

        Thread.sleep( 100 );//這是故意讓A在B前面執行

        new Thread( ()->{
            try {
                phone2.sendMessage();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();
    }

 

一個靜態同步方法,一個普通同步方法,同一部手機,先打印郵件還是短信(普通同步方法)      答案: 短信
當一個線程視圖訪問同步代碼塊時,它首先必須得到鎖,推出或拋出異常時必須釋放鎖。
也就是說如果一個實例對象的非靜態同步方法獲取鎖後,該實例對象的其他非靜態同步方法必須等待獲取鎖的方法後才能獲取鎖,
可是別的實例對象的非靜態同步方法因爲跟該實例對象的非靜態同步方法用的時不同的鎖,

所有的靜態同步方法用的也是一把鎖-類對象本身
這兩把鎖時兩個不同的對象,所以靜態同步方法與非靜態同步方法之間時不會有靜態條件的
但是一旦一個靜態同步方法獲取鎖後,其他的靜態同步方法都必須等待該方法釋放鎖後才能獲取鎖
還是不同的實例對象的靜態同步方法之間,只要他們同一個類的實例對象

通俗的說法:

static鎖的是大門(字節碼文件),普通synchronize鎖的是大門裏面的一扇門,它的關閉不影響大門,也與大門無關(鎖對象)

class Phone//Phone.java ---> Phone.class    Class.forName()
{
    public static synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(3);//新的寫法
        //Thread.sleep(4000);//暫停3秒鐘
        System.out.println("發郵件");
    }

    public synchronized void sendMessage() throws Exception{
        System.out.println("發短信");
    }
}


    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread( ()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();

        Thread.sleep( 100 );//這是故意讓A在B前面執行

        new Thread( ()->{
            try {
                phone.sendMessage();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();
    }

 

8

一個靜態同步方法,一個普通同步方法,兩部手機,請問先打印郵件還是短信  答案:短信

一個鎖類對象,一個鎖對象,互不影響。

    public static synchronized void sendEmail() throws Exception{
        TimeUnit.SECONDS.sleep(3);//新的寫法
        //Thread.sleep(4000);//暫停3秒鐘
        System.out.println("發郵件");
    }

    public synchronized void sendMessage() throws Exception{
        System.out.println("發短信");
    }


    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread( ()->{
            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"A").start();

        Thread.sleep( 100 );//這是故意讓A在B前面執行

        new Thread( ()->{
            try {
                phone2.sendMessage();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"B").start();
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章