天天看點

lock8鎖詳解現象深入了解

8鎖現象

如何判斷鎖的是誰!永遠的知道什麼鎖,鎖到底鎖的是誰!

深刻了解我們的鎖

1、标準通路,先發送郵件還是短信 Email 鎖是this
2、暫停3S在郵件方法裡,先發送郵件還是短信 Email 鎖是this
3、新增hello普通方法,先發送郵件還是hello hello 加個普通方法後發現和同步鎖無關
4、有兩部手機,先發送郵件還是短信 EMS 鎖是兩個不同的this,但是需要隔4s才能發送email
5、兩個靜态同步方法,有一部手機,先發送郵件還是短信 Email 鎖的是同一個Class對象
6、一個普通同步方法,一個靜态同步方法,一部手機,先發送郵件還是短信 EMS 兩個鎖,一個是this,一個是Class,但是需要隔4s才能發送email
7、兩個靜态同步方法,有2部手機,先發送郵件還是短信 Email 鎖的是同一個Class對象
8、一個普通同步方法,一個靜态同步方法,2部手機,先發送郵件還是短信 EMS 兩個鎖,一個是this,一個是Class,但是需要隔4s才能發送email
  1. 标準情況下 是先sendEmail() 還是先sendEMS()?

    答案:

    sendEmail

    解釋:被 synchronized 修飾的方式,鎖的對象是方法的調用者

    是以說這裡兩個方法調用的對象是同一個,先調用的先執行!

    import java.util.concurrent.TimeUnit;
    
    public class LockDemo1 {
        public static void main(String[] args) throws InterruptedException {
            Phone1 phone1 = new Phone1();
            new Thread(()->{
                phone1.sendEmail();
            },"A").start();
            TimeUnit.SECONDS.sleep(2);
            new Thread(()->{
                phone1.sendEMS();
            },"B").start();
        }
    }
    class Phone1{
        public synchronized void sendEmail(){
            System.out.println("senEmail");
        }
        public synchronized  void sendEMS(){
            System.out.println("sendEMS");
        }
    }
               
  2. sendEmail()休眠3s後 是先sendEmail() 還是先sendEMS()?

    答案:

    sendEmail

    解釋:被 synchronized 修飾的方式,鎖的對象是方法的調用者

    是以說這裡兩個方法調用的對象是同一個,先調用的先執行!

    import java.util.concurrent.TimeUnit;
    
    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);
            new Thread(()->{
                phone2.sendEMS();
            },"B").start();
        }
    }
    class Phone2{
        public synchronized void sendEmail() throws InterruptedException {
            TimeUnit.SECONDS.sleep(3);
            System.out.println("sendEmail");
        }
        public synchronized void sendEMS(){
            System.out.println("sendEMS");
        }
    }
               
  3. 一部手機, 被synchronized 修飾的方式和普通方法 先執行sendEmail() 還是 sendEMS()

    答案:

    sendEMS

    解釋:新增加的這個方法沒有 synchronized 修飾,不是同步方法,不受鎖的影響!
    import java.util.concurrent.TimeUnit;
    
    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.sendEMS();
            },"B").start();
        }
    }
    class Phone3{
        public synchronized void sendEmail() throws InterruptedException {
            TimeUnit.SECONDS.sleep(3);
            System.out.println("sendEmail");
        }
    
        // 沒有synchronized 沒有static 就是普通方式
        public void sendEMS(){
            System.out.println("sendEMS");
        }
    }
               
  4. 兩部手機,被synchronized 修飾的不同方法 先執行sendEmail() 還是sendEMS()?

    答案:

    sendEMS

    解釋:被synchronized 修飾的不同方法 鎖的對象是調用者

    這裡鎖的是

    兩個不同的調用者

    ,所有互不影響
    import java.util.concurrent.TimeUnit;
    
    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(2);
            new Thread(()->{
                phoneB.sendEMS();
            },"B").start();
        }
    }
    class Phone4{
        public synchronized void sendEmail() throws InterruptedException {
            TimeUnit.SECONDS.sleep(3);
            System.out.println("sendEmail");
        }
        public synchronized void sendEMS(){
            System.out.println("sendEMS");
        }
    }
               
  5. 一部手機,兩個靜态同步方法 都被synchronized 修飾 是先sendEmail() 還是sendEMS()?

    答案:

    sendEmial

    解釋:隻要方法被 static 修飾,鎖的對象就是

    Class模闆對象,這個則全局唯一

    是以說這裡是同一個鎖,并不是因為synchronized 這裡程式會從上往下依次執行

    import java.util.concurrent.TimeUnit;
    
    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(2);
            new Thread(()->{
                phone5.sendEMS();
            },"B").start();
        }
    }
    class Phone5{
        public static synchronized void sendEmail() throws InterruptedException {
            TimeUnit.SECONDS.sleep(3);
            System.out.println("sendEmail");
        }
    
        public static synchronized void sendEMS(){
            System.out.println("sendEMS");
        }
    }
               
  6. 一部手機,被synchronized 修飾的普通方法和靜态方法 是先sendEmail() 還是 sendEMS()?

    答案:

    sendEMS

    解釋:

    隻要被static修飾鎖的是class模闆

    , 而synchronized 鎖的是調用的對象

    這裡是兩個鎖互不影響,按時間先後執行

    import java.util.concurrent.TimeUnit;
    
    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(2);
            new Thread(()->{
                phone6.sendEMS();
            },"B").start();
        }
    }
    class Phone6{
        public static synchronized void sendEmail() throws InterruptedException {
            TimeUnit.SECONDS.sleep(3);
            System.out.println("sendEmail");
        }
    
        public synchronized void sendEMS(){
            System.out.println("sendEMS");
        }
    }
               
  7. 兩部手機,同被static+synchronized 修飾的兩個方法,是先sendEmail()還是sendEMS()?

答案:

sendEmail

解釋:隻要方法被 static 修飾,鎖的對象就是 Class模闆對象,這個則全局唯一

是以說這裡是同一個鎖,并不是因為synchronized

import java.util.concurrent.TimeUnit;

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(2);
        new Thread(()->{
            phoneB.sendEMS();
        },"B").start();
    }
}
class Phone7{
    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }

    public static synchronized void sendEMS(){
        System.out.println("sendEMS");
    }
}
           
  1. 兩部手機,一個被static+synchronized 修飾的方法和普通的synchronized方法,先執行sendEmail()還是sendEMS()?

    答案:

    sendEMS()

    解釋: 隻要被static 修飾的鎖的就是整個class模闆

    這裡一個鎖的是class模闆 一個鎖的是調用者

    是以鎖的是兩個對象 互不影響

    import java.util.concurrent.TimeUnit;
    
    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(2);
            new Thread(()->{
                phoneB.sendEMS();
            },"B").start();
        }
    }
    class Phone8{
        public static synchronized void sendEmail() throws InterruptedException {
            TimeUnit.SECONDS.sleep(3);
            System.out.println("sendEmail");
        }
    
        public synchronized void sendEMS(){
            System.out.println("sendEMS");
        }
    }
               
小結

new this 具體的一個手機

static Class 唯一的一個模版