JUC- 八锁现象

4.1 标准访问

package cn.guardwhy.test04;

import java.util.concurrent.TimeUnit;

/*
* 标准访问:先发短信还是打电话?
*/
public class LockTest01 {
    
    
    public static void main(String[] args) {
    
    
        // 创建phone对象
        Phone phone = new Phone();

        new Thread(()->{
    
    
            phone.sendMessage();
        }, "curry").start();

        try {
    
    
            // 睡眠1s
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

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

// 手机类
class Phone{
    
    
    public synchronized void sendMessage(){
    
    

        System.out.println("发短信...");
    }

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

执行结果

总结

synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以当两个方法用的是同一个锁,先调用方法的先执行

4.2 短信暂停5s

package cn.guardwhy.test04;

import java.util.concurrent.TimeUnit;

/*
* 发短信延迟5s,谁先访问?
*/
public class LockTest01 {
    
    
    public static void main(String[] args) {
    
    
        // 创建phone对象
        Phone phone = new Phone();

        new Thread(()->{
    
    
            phone.sendMessage();
        }, "curry").start();

        try {
    
    
            // 睡眠1s
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

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

// 手机类
class Phone{
    
    
    public synchronized void sendMessage(){
    
    

        try {
    
    
            // 睡眠5s
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信...");
    }

    public synchronized void call(){
    
    

        try {
    
    
            // 睡眠5s
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("打电话...");
    }
}

执行结果

结论:

synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行,第二个方法只有在第一个方法执行完释放锁之后才能执行。

4.3 新增普通方法

package cn.guardwhy.test04;

import java.util.concurrent.TimeUnit;

/*
新增一个普通方法test(),请问先打短信还是test?
*/
public class LockTest02 {
    
    
    public static void main(String[] args) {
    
    
        // 创建phone对象
        Phone2 phone2 = new Phone2();

        new Thread(()->{
    
    
            phone2.sendMessage();
        }, "curry").start();

        try {
    
    
            // 睡眠1s
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        new Thread(()->{
    
    
            phone2.test();
        }, "kobe").start();
    }
}

// 手机类
class Phone2{
    
    
    public synchronized void sendMessage(){
    
    

        try {
    
    
            // 睡眠5s
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信...");
    }

    public synchronized void call(){
    
    
        System.out.println("打电话...");
    }
    // 普通方法
    public void test(){
    
    
        System.out.println("hello world!!!");
    }
}

执行结果

总结:

新增的方法没有被synchronized修饰,不是同步方法,不受锁的影响,所以不需要等待。其他线程共用了一把锁,所以还需要等待。

4.4 两个对象

package cn.guardwhy.test04;

import java.util.concurrent.TimeUnit;

/*
两部手机、先call还是sendMessage?
*/
public class LockTest03 {
    
    
    public static void main(String[] args) {
    
    
        // 创建phone对象,两个对象,两个调用者,两把锁
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();

        new Thread(()->{
    
    
            phone1.sendMessage();
        }, "curry").start();

        try {
    
    
            // 睡眠1s
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        new Thread(()->{
    
    
            phone2.call();
        }, "kobe").start();
    }
}

// 手机类
class Phone3{
    
    
    public synchronized void sendMessage(){
    
    

        try {
    
    
            // 睡眠5s
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信...");
    }

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

}

执行结果

总结

被synchronized修饰的方法,锁的对象是方法的调用者。因为用了两个对象调用各自的方法,所以两个方法的调用者不是同一个,两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法

4.5 静态同步方法(同对象)

package cn.guardwhy.test04;

import java.util.concurrent.TimeUnit;

/*
 * 两个静态同步方法,同一部手机,先发短信还是打电话?
 */
public class LockTest04 {
    
    
    public static void main(String[] args) {
    
    
        // 创建phone对象
        Phone4 phone4 = new Phone4();

        new Thread(()->{
    
    
            phone4.sendMessage();
        }, "curry").start();

        try {
    
    
            // 睡眠1s
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        new Thread(()->{
    
    
            phone4.call();
        }, "kobe").start();
    }
}

// Phone4是唯一的class对象
class Phone4{
    
    
    /*
    * synchronized锁的对象是方法的调用者,static是静态方法。
    * 静态方法类一加载就有了!!锁的是Class
    */
    public static synchronized void sendMessage(){
    
    

        try {
    
    
            // 睡眠5s
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信...");
    }

    public static synchronized void call(){
    
    

        System.out.println("打电话...");
    }
}

执行结果

总结:

被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,所以两个方法用的是同一个锁,后调用的方法需要等待先调用的方法。

4.6 静态同步方法(两对象)

package cn.guardwhy.test04;

import java.util.concurrent.TimeUnit;

/*
 * 两个静态同步方法,同一部手机,先发短信还是打电话?
 */
public class LockTest05 {
    
    
    public static void main(String[] args) {
    
    
        // 两个对象的Class类模板只有一个,Static,锁的是Class.
        Phone5 phone1 = new Phone5();
        Phone5 phone2 = new Phone5();

        new Thread(()->{
    
    
            phone1.sendMessage();
        }, "curry").start();

        try {
    
    
            // 睡眠1s
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        new Thread(()->{
    
    
            phone2.call();
        }, "kobe").start();
    }
}

// Phone5是唯一的class对象
class Phone5{
    
    
    /*
     * synchronized锁的对象是方法的调用者,static是静态方法。
     * 静态方法类一加载就有了!!锁的是Class
     */
    public static synchronized void sendMessage(){
    
    

        try {
    
    
            // 睡眠5s
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信...");
    }

    public static synchronized void call(){
    
    

        System.out.println("打电话...");
    }
}

执行结果

总结:

被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,即便用了两个不同的对象调用方法,两个方法用的还是同一个锁,后调用的方法需要等待先调用的方法。

4.7 普通方法和静态方法(同一对象)

package cn.guardwhy.test06;

import java.util.concurrent.TimeUnit;

/*
 * 一个普通同步方法,一个静态同步方法,同一个对象,先发短信还是打电话?
 */
public class LockTest01 {
    
    
    public static void main(String[] args) {
    
    
       Phone phone1 = new Phone();

        new Thread(()->{
    
    
            phone1.sendMessage();
        }, "curry").start();

        try {
    
    
            // 睡眠1s
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        new Thread(()->{
    
    
            phone1.call();
        }, "kobe").start();
    }
}


class Phone{
    
    
    /*
     * synchronized锁的对象是方法的调用者,static是静态方法。
     * 静态方法类一加载就有了!!锁的是Class
     */
    public static synchronized void sendMessage(){
    
    

        try {
    
    
            // 睡眠5s
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信...");
    }

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

执行结果

总结:

被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法锁的对象不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

4.8 普通方法和静态方法(两个对象)

package cn.guardwhy.test06;

import java.util.concurrent.TimeUnit;

/*
 * 一个普通同步方法,一个静态同步方法,同一个对象,先发短信还是打电话?
 */
public class LockTest01 {
    
    
    public static void main(String[] args) {
    
    
       Phone phone1 = new Phone();
       Phone phone2 = new Phone();

        new Thread(()->{
    
    
            phone1.sendMessage();
        }, "curry").start();

        try {
    
    
            // 睡眠1s
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        new Thread(()->{
    
    
            phone2.call();
        }, "kobe").start();
    }
}


class Phone{
    
    
    // 静态的同步方法:锁的是Class类模板
    public static synchronized void sendMessage(){
    
    

        try {
    
    
            // 睡眠5s
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("发短信...");
    }
    
    // 普通的同步方法: 锁的是调用者
    public synchronized void call(){
    
    
        System.out.println("打电话...");
    }
}

执行结果

总结:
被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。即便是用同一个对象调用两个方法,锁的对象也不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。

4.9 八锁现象总结

对于普通同步方法,锁的是当前实例对象。
对于静态同步方法,锁的是当前的Class对象。
对于同步方法块,锁是synchronized括号里面的配置对象。

猜你喜欢

转载自blog.csdn.net/hxy1625309592/article/details/113948193