/**
 * 8 锁,就是关于锁的8个问题
 * 1、标准情况下,两个线程打印,发短信还是打电话:先打印发短信
 * 2、sendSms延迟4秒,两个线程打印,发短信还是打电话:还是先打印发短信
 */
public class Test1 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        //锁的问题
        new Thread(()->{
            phone.sendSms();
        },"A").start();

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

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

}

class Phone {

    //synchronized 锁的对象是方法的调用者
    //两个方法是同一锁,谁先拿到谁先执行

    public synchronized void sendSms() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public synchronized void call() {
        System.out.println("打电话");
    }
}
/**
 * 8 锁,就是关于锁的8个问题
 * 3、增加了一个普通方法后,先打印发短信还是hello:先打印普通方法
 * 4、两个对象,两个同步方法,先打印发短信还是打电话:先打印打电话
 */
public class Test2 {
    public static void main(String[] args) {
        //两个对象,两个调用者,两把锁
        Phone2 phone1 = new Phone2();
        Phone2 phone2 = new Phone2();

        //锁的问题
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

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

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

}

class Phone2 {

    //synchronized 锁的对象是方法的调用者

    public synchronized void sendSms() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public synchronized void call() {
        System.out.println("打电话");
    }

    //这里没有锁,不是同步方法,不受锁的影响
    public void hello() {
        System.out.println("hello");
    }
}
/**
 * 5、增加两个静态的同步方法,只有一个对象,先打印:发短信
 * 6、两个对象,增加两个静态的同步方法,先打印:发短信 ,对比不是静态方法的结果
 */

public class Test3 {
    public static void main(String[] args) {
        //两个对象的Class类模板只有一个,static,锁的是Class
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();

        //锁的问题
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}

// Phone3 唯一的一个Class对象
class Phone3 {

    //synchronized 锁的对象是方法的调用者
    //static 静态方法
    //类一加载就有了,锁的是Class 模版

    public static synchronized void sendSms() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    public static synchronized void call() {
        System.out.println("打电话");
    }

    //这里没有锁,不是同步方法,不受锁的影响
    public void hello() {
        System.out.println("hello");
    }
}
/**
 * 7、1个静态的同步方法,1个普通的同步方法,一个对象,先打印:打电话,四秒后发短信,因为是两个锁,一个是类Class模板的锁,一个是对象的锁
 * 8、1个静态的同步方法,1个普通的同步方法,两个对象,先打印:打电话,四秒后发短信,因为是两个锁
 */
public class Test4 {
    public static void main(String[] args) {
        //两个对象的Class类模板只有一个,static,锁的是Class
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();

        //锁的问题
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}

// Phone3 唯一的一个Class对象
class Phone4 {

    //静态的同步方法 锁的是Class类模板
    //区分类对象和实例对象
    public static synchronized void sendSms() {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }

    //普通的同步方法 锁的调用者
    public synchronized void call() {
        System.out.println("打电话");
    }

    //这里没有锁,不是同步方法,不受锁的影响
    public void hello() {
        System.out.println("hello");
    }
}