线程8锁

场景一

package com.myc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 问题1:先执行 call,还是先执行 send?
 * 答:call
 * 被 synchronized 修饰的方法,锁的对象是方法的调用者,也就是phone
 *  先调用的先拿到锁,就会先执行
 */
@SuppressWarnings("all")
public class Demo1 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() ->{
            phone.call();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


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

class Phone{
    //synchronized锁的对象是方法的调用者,也就是Phone的实例
    //两个方法使用的是同一个锁,谁先拿到,谁就执行
    public synchronized void call(){
        System.out.println("打电话");
    }

    public synchronized void  send(){
        System.out.println("发短信");
    }

}

场景二

package com.myc.lock8;

import java.util.concurrent.TimeUnit;

/**
 *问题2:call 方法休眠4秒后,先执行那个call 还是 send
 *   答:call
 *   被锁的仍是方法的调用者,phone,call 先调用拿到锁,休眠不会释放锁,call 执行完send 才会执行
 *
 */
@SuppressWarnings("all")
public class Demo2 {
    public static void main(String[] args) {
        Phone2 phone = new Phone2();
        new Thread(() ->{
            try {
                phone.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


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

class Phone2{
    //synchronized锁的对象是方法的调用者,也就是Phone的实例
    //两个方法使用的是同一个锁,谁先拿到,谁就执行
    public synchronized void call() throws InterruptedException {

        TimeUnit.SECONDS.sleep(4);
        System.out.println("打电话");
    }

    public synchronized void  send(){
        System.out.println("发短信");
    }

}

场景三

package com.myc.lock8;

import java.util.concurrent.TimeUnit;

/**
 *问题3:被synchronized 修饰的方法 和普通的方法,谁先被调用
 *   答:hello
 *   call 和 send 需要锁才能执行, hello 不受影响,如果call休眠的时间小于等于4秒,call先执行
 *
 */
@SuppressWarnings("all")
public class Demo3 {
    public static void main(String[] args) {
        Phone3 phone = new Phone3();
        new Thread(() ->{
            try {
                phone.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


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

class Phone3{

    public synchronized void call() throws InterruptedException {

        TimeUnit.SECONDS.sleep(4);
        System.out.println("打电话");
    }

    public synchronized void  send(){
        System.out.println("发短信");
    }
    public void hello(){
        System.out.println("说Hello");
    }

}

场景四

package com.myc.lock8;

import java.util.concurrent.TimeUnit;

/**
 *问题4:被synchronized 修饰的不同方法 先执行send() 还是call()?
 *   答:send
 *   被锁的仍是方法的调用者,phone1 和 phone2 是两把不同的锁,call休眠的时间长 ,send先执行
 *
 */
@SuppressWarnings("all")
public class Demo4 {
    public static void main(String[] args) {
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        new Thread(() ->{
            try {
                phone1.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


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

class Phone4{

    public synchronized void call() throws InterruptedException {

        TimeUnit.SECONDS.sleep(4);
        System.out.println("打电话");
    }

    public synchronized void  send(){
        System.out.println("发短信");
    }

}

场景五

package com.myc.lock8;

import java.util.concurrent.TimeUnit;

/**
 *问题5:两个静态的同步方法,都被Synthronized 修饰,先执行 call 还是 send
 *   答:call
 *   只要方法被 static 修饰,锁的对象就是 Class模板对象,这个则全局唯一!
 *   所以说这里是同一个锁,并不是因为synchronized  这里程序会从上往下依次执行
 *
 */
@SuppressWarnings("all")
public class Demo5 {
    public static void main(String[] args) {
        Phone7 phone = new Phone7();
        new Thread(() ->{
            try {
                phone.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


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

class Phone5{

    public static synchronized void call() throws InterruptedException {

        TimeUnit.SECONDS.sleep(4);
        System.out.println("打电话");
    }

    public static synchronized void  send(){
        System.out.println("发短信");
    }

}

场景六

package com.myc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 问题6::被synchronized 修饰的普通方法和静态方法  是先send还是 call
 * 答案:send
 * 解释:只要被static修饰锁的是class模板, 而synchronized 锁的是调用的对象
 * 这里是两个锁互不影响,按时间先后执行
 *
 */
@SuppressWarnings("all")
public class Demo6 {
    public static void main(String[] args) {
        Phone6 phone = new Phone6();
        new Thread(() ->{
            try {
                phone.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


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

class Phone6{
    public static synchronized void call() throws InterruptedException {

        TimeUnit.SECONDS.sleep(4);
        System.out.println("打电话");
    }

    public  synchronized void  send(){
        System.out.println("发短信");
    }

}

场景七

package com.myc.lock8;

import java.util.concurrent.TimeUnit;

/**
 *问题7:两个不同的对象分别调用两个静态的同步方法,都被Synthronized 修饰,先执行 call 还是 send
 *   答:call
 *   只要方法被 static 修饰,锁的对象就是 Class模板对象,这个则全局唯一,phone1和phone2用
 *   的是同一个锁,并不是因为synchronized  这里程序会从上往下依次执行
 *
 */
@SuppressWarnings("all")
public class Demo7 {
    public static void main(String[] args) {
        Phone7 phone1 = new Phone7();
        Phone7 phone2 = new Phone7();
        new Thread(() ->{
            try {
                phone1.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


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

class Phone7{

    public static synchronized void call() throws InterruptedException {

        TimeUnit.SECONDS.sleep(4);
        System.out.println("打电话");
    }

    public static synchronized void  send(){
        System.out.println("发短信");
    }

}

场景八

package com.myc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 问题8::一个被static+synchronized 修饰的方法和普通的synchronized方法,先执行send还是call?
 * 答案:send
 * 解释:只要被static修饰锁的是class模板, 而synchronized 锁的是调用的对象
 * 这里是两个锁互不影响,按时间先后执行
 *
 */
@SuppressWarnings("all")
public class Demo8 {
    public static void main(String[] args) {
        Phone8 phone1 = new Phone8();
        Phone8 phone2 = new Phone8();
        new Thread(() ->{
            try {
                phone1.call();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


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

class Phone8{
    public static synchronized void call() throws InterruptedException {

        TimeUnit.SECONDS.sleep(4);
        System.out.println("打电话");
    }

    public  synchronized void  send(){
        System.out.println("发短信");
    }

}

小结

  1. 被static + synchronized 修饰的方法锁的是类,被 synchronized 修饰的方法锁的是类的实例,分别调用两种方法,使用的肯定是两把锁,互不影响
  2. 被static + synchronized 修饰的两种方法,无论几个实例,调用的都是类本身的锁
  3. 只被 synchronized 修饰的两种方法 ,一个实例调用是一把锁,两个实例调用就是两个不同的锁
posted @ 2021-08-24 16:53  kokurachiyo  阅读(217)  评论(0)    收藏  举报