經典8鎖問題--助你徹底搞懂鎖的概念


下面將通過經典的8鎖問題,認清鎖原理

場景一

import java.util.concurrent.TimeUnit;

/**
 * 標准情況下 是先sendEmail() 還是先callPhone()?
 * 答案:sendEmail
 * 解釋:被 synchronized 修飾的方式,鎖的對象是方法的調用者
 * 所以說這里兩個方法調用的對象是同一個,先調用的先執行!
 */
public class LockDemo1 {
    public static void main(String[] args) throws InterruptedException {
        Phone1 phone1 = new Phone1();
        new Thread(()->{
            phone1.sendEmail();
        },"A").start();
        TimeUnit.SECONDS.sleep(3);
        new Thread(()->{
            phone1.callPhone();
        },"B").start();
    }
}
class Phone1{
    public synchronized void sendEmail(){
        System.out.println("senEmail");
    }
    public synchronized  void callPhone(){
        System.out.println("callPhone");
    }
}

場景二

import java.util.concurrent.TimeUnit;

/**
 * sendEmail()休眠三秒后  是先執行sendEmail() 還是 callPhone()
 * 答案: sendEmail
 * 解釋:被 synchronized 修飾的方式,鎖的對象是方法的調用者
 * 所以說這里兩個方法調用的對象是同一個,先調用的先執行!
 */
public class LockDemo2 {
    public static void main(String[] args) throws InterruptedException {
        Phone2 phone2 = new Phone2();
        new Thread(()->{
            try {
                phone2.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        TimeUnit.SECONDS.sleep(2); // 休眠2秒
        new Thread(()->{
            phone2.callPhone();
        },"B").start();
    }
}
class Phone2{
    public synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }
    public synchronized void callPhone(){
        System.out.println("callPhone");
    }
}

場景三

import java.util.concurrent.TimeUnit;

/**
 * 被synchronized 修飾的方式和普通方法 先執行sendEmail() 還是 callPhone()
 * 答案: callPhone
 * 解釋:新增加的這個方法沒有 synchronized 修飾,不是同步方法,不受鎖的影響!
 */
public class LockDemo3 {
    public static void main(String[] args) throws InterruptedException {
        Phone3 phone3 = new Phone3();
        new Thread(()->{
            try {
                phone3.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(2);
        new Thread(()->{
            phone3.callPhone();
        },"B").start();
    }
}
class Phone3{
    public synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("sendEmail");
    }

    // 沒有synchronized 沒有static 就是普通方式
    public void callPhone(){
        System.out.println("callPhone");
    }
}

場景四

import java.util.concurrent.TimeUnit;

/**
 * 被synchronized 修飾的不同方法 先執行sendEmail() 還是callPhone()?
 * 答案:callPhone
 * 解釋:被synchronized 修飾的不同方法 鎖的對象是調用者
 * 這里鎖的是兩個不同的調用者,所有互不影響
 */
public class LockDemo4 {
    public static void main(String[] args) throws InterruptedException {
        Phone4 phoneA = new Phone4();
        Phone4 phoneB = new Phone4();

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

        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phoneB.callPhone();
        },"B").start();
    }
}
class Phone4{
    public synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }
    public synchronized void callPhone(){
        System.out.println("callPhone");
    }
}

場景五

import java.util.concurrent.TimeUnit;

/**
 * 兩個靜態同步方法 都被synchronized 修飾 是先sendEmail() 還是callPhone()?
 * 答案:sendEmial
 * 解釋:只要方法被 static 修飾,鎖的對象就是 Class模板對象,這個則全局唯一!
 *      所以說這里是同一個鎖,並不是因為synchronized  這里程序會從上往下依次執行
 */
public class LockDemo5 {
    public static void main(String[] args) throws InterruptedException {
        Phone5 phone5 = new Phone5();
        new Thread(()->{
            try {
                phone5.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone5.callPhone();
        },"B").start();
    }
}
class Phone5{
    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }

    public static synchronized void callPhone(){
        System.out.println("callPhone");
    }
}

場景六

import java.util.concurrent.TimeUnit;

/**
 * 被synchronized 修飾的普通方法和靜態方法  是先sendEmail() 還是 callPhone()?
 * 答案:callPhone
 * 解釋:只要被static修飾鎖的是class模板, 而synchronized 鎖的是調用的對象
 * 這里是兩個鎖互不影響,按時間先后執行
 */
public class LockDemo6 {
    public static void main(String[] args) throws InterruptedException {
        Phone6 phone6 = new Phone6();
        new Thread(()->{
            try {
                phone6.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phone6.callPhone();
        },"B").start();
    }
}
class Phone6{
    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }

    public synchronized void callPhone(){
        System.out.println("callPhone");
    }
}

場景七

import java.util.concurrent.TimeUnit;

/**
 * 同被static+synchronized 修飾的兩個方法,是先sendEmail()還是callPhone()?
 *  答案:sendEmail
 *  解釋:只要方法被 static 修飾,鎖的對象就是 Class模板對象,這個則全局唯一
 *  所以說這里是同一個鎖,並不是因為synchronized
 */
public class LockDemo7 {
    public static void main(String[] args) throws InterruptedException {
        Phone7 phoneA = new Phone7();
        Phone7 phoneB = new Phone7();

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

        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phoneB.callPhone();
        },"B").start();
    }
}
class Phone7{
    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }

    public static synchronized void callPhone(){
        System.out.println("callPhone");
    }
}

場景八

import java.util.concurrent.TimeUnit;

/**
 * 一個被static+synchronized 修飾的方法和普通的synchronized方法,先執行sendEmail()還是callPhone()?
 * 答案:callPhone()
 * 解釋: 只要被static 修飾的鎖的就是整個class模板
 * 這里一個鎖的是class模板 一個鎖的是調用者 
 * 所以鎖的是兩個對象 互不影響
 */
public class LockDemo8 {
    public static void main(String[] args) throws InterruptedException {
        Phone8 phoneA = new Phone8();
        Phone8 phoneB = new Phone8();

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

        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{
            phoneB.callPhone();
        },"B").start();
    }
}
class Phone8{
    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }

    public synchronized void callPhone(){
        System.out.println("callPhone");
    }
}

小結:

synchronized(Demo.class){

}
synchronized(this){

}

1、new this 調用的是這個對象,是一個具體的對象!
2、static class 唯一的一個模板!
在我們編寫多線程程序得時候,只需要搞明白這個到底鎖的是什么就不會出錯了!


免責聲明!

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



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