synchronized 八锁现象,搞懂 synchronized 的使用问题

前言

synchronized 八锁现象,就是 synchronized 使用中的八个问题,下面我们一一了解下。

一.同一个对象,两个线程分别调用对象的两个加锁方法

package com.example.demo.module.synchronized8Test;

import java.util.concurrent.TimeUnit;

public class Test {

    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 void sendSms(){
        System.out.println("----发短信----");
    }

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

}

运行结果
在这里插入图片描述
结论:
synchronized 在普通方法上修饰时,锁的对象是方法调用者,该示例中都是同一对象 phone 调用两个用 synchronized 修饰的普通方法 sendSms call,所以哪个线程先拿到锁哪个线程就先执行。

二.同一个对象,两个线程分别调用对象的两个加锁方法,sendSms 方法加上延迟3秒

package com.example.demo.module.synchronized8Test;

import java.util.concurrent.TimeUnit;

public class Test {

    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 void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

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

}

运行结果
在这里插入图片描述
结论:
synchronized 在普通方法上修饰时,锁的对象是方法调用者,该示例中都是同一对象 phone 调用两个用 synchronized 修饰的普通方法 sendSms call,所以哪个线程先拿到锁哪个线程就先执行。

三.同一个对象,两个线程分别调用对象的加锁方法和无锁方法,sendSms 方法加上延迟3秒

package com.example.demo.module.synchronized8Test;

import java.util.concurrent.TimeUnit;

public class Test {

    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::hello,"B").start();

    }

}

class Phone{

    synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

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

    void hello(){
        System.out.println("----hello----");
    }

}

运行结果
在这里插入图片描述
结论:
hello 方法未加锁,所以不受锁的限制,线程 B 延迟1秒后将直接执行 hello 方法,无需等待线程 A。

四.不同对象,调用各自的加锁方法,sendSms 方法加上延迟3秒

package com.example.demo.module.synchronized8Test;

import java.util.concurrent.TimeUnit;

public class Test {

    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        new Thread(phone1::sendSms,"A").start();

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

        new Thread(phone2::call,"B").start();

    }

}

class Phone{

    synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

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

}

运行结果
在这里插入图片描述
结论:
synchronized 在普通方法上修饰时,锁的对象是方法调用者,该示例中对象 phone1 调用 sendSms 方法,对象 phone2 调用 call 方法,sendSms 方法锁的是 对象 phone1call 方法锁的是对象 phone2 ,是两把不同的锁,互不影响。

五.同一个对象,两个线程分别调用对象的两个静态加锁方法,sendSms 方法加上延迟3秒

package com.example.demo.module.synchronized8Test;

import java.util.concurrent.TimeUnit;

public class Test {

    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{

    static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

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

}

运行结果
在这里插入图片描述
结论:
synchronized 在静态方法上修饰时,锁的对象是 Class,该示例中同一对象 phone 调用两个用 synchronized 修饰的静态方法 sendSms call,为同一把锁,所以从上到下执行。

六.不同对象,调用各自的静态加锁方法,sendSms 方法加上延迟3秒

package com.example.demo.module.synchronized8Test;

import java.util.concurrent.TimeUnit;

public class Test {

    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            phone1.sendSms();
        },"A").start();

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

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

    }

}

class Phone{

    static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

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

}

运行结果
在这里插入图片描述
结论:
synchronized 在静态方法上修饰时,锁的对象是 Class,该示例中对象 phone1 调用静态锁方法 sendSms ,对象 phone2 调用静态锁方法 call,对象 phone1 phone2 的类模板都是 Phone.class,所以为同一把锁,所以从上到下执行。

七.同一个对象,两个线程分别调用对象的静态加锁方法和普通加锁方法,sendSms 方法加上延迟3秒

package com.example.demo.module.synchronized8Test;

import java.util.concurrent.TimeUnit;

public class Test {

    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{

    static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

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

}

运行结果
在这里插入图片描述
结论:
线程 A 调用静态加锁方法 sendSms ,锁的是 Phone.class,线程 B 调用普通加锁方法 call,锁的是对象 phone,是两把不同的锁,互不影响。

八.不同对象,分别调用静态加锁方法和普通加锁方法,sendSms 方法加上延迟3秒

package com.example.demo.module.synchronized8Test;

import java.util.concurrent.TimeUnit;

public class Test {

    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            phone1.sendSms();
        },"A").start();

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

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

    }

}

class Phone{

    static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

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

}

运行结果
在这里插入图片描述
结论:
对象 phone1 调用静态加锁方法 sendSms ,锁的是 Phone.class,对象 phone2 调用普通加锁方法 call,锁的是对象 phone2,是两把不同的锁,互不影响。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值