多线程8锁问题 详解

多线程8锁问题详解

1.案例准备

首先我们准备一个资源类,在资源类定义两个同步方法,来测试在不同的访问方式下,

会产生什么样的结果。代码如下:

class MyPhone {

    public synchronized void sendEmail() {
        // 发送邮件
        System.out.println("----sendEmail");
    }

    // 发送短信
    public synchronized void sendMS() {
        System.out.println("----sendMS");
    }
}

2.第一锁,标准访问是先打印邮件还是短信

我们编写如下代码进行测试

public class Lock8Demo {
    public static void main(String[] args) throws InterruptedException {
        MyPhone myPhone = new MyPhone();

        new Thread(() -> {
            myPhone.sendMS();
        }, "线程二").start();
        new Thread(() -> {
            myPhone.sendEmail();
        }, "线程一").start();

    }
}

我们发现在标准访问下,线程一和线程二都有可能先执行

第二锁,邮件方法暂停2秒,是先打印邮件还是短信

资源类修改如下:

class MyPhone {

    public synchronized void sendEmail() {
        // 发送邮件
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("----sendEmail");
    }

    // 发送短信
    public synchronized void sendMS() {
        System.out.println("----sendMS");
    }
}

测试代码如下:

public class Lock8Demo {
    public static void main(String[] args) throws InterruptedException {
        MyPhone myPhone = new MyPhone();

        new Thread(() -> {
            myPhone.sendMS();
        }, "线程二").start();
        Thread.sleep(200);
        new Thread(() -> {
            myPhone.sendEmail();
        }, "线程一").start();

    }
}

为了方便测试,我们在线程一一和线程二之间休眠2秒,保证线程一先调用,此后同样。

在这样的访问方式下,会先发送邮件,因为在同一个对象里如果有多个synchronized方法或synchronized代码块,某一个时刻内,只要有一个线程去调用了其中一个synchronized方法,其它线程只能等待,换句话说,某一个时刻内,只能有一个线程去访问这些synchronized方法,在本例中即使是线程一休眠了2秒,因为它先调用资源类,所以线程二会等待线程一执行完才会执行。

第三锁,新增一个普通方法hello,会先打印邮件还是hello
class MyPhone {

    public synchronized void sendEmail() {
        // 发送邮件
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("----sendEmail");
    }

    // 发送短信
    public synchronized void sendMS() {
        System.out.println("----sendMS");

    }

    // 普通方法hello
    public void hello() {
        System.out.println("----hello");
    }
}

测试代码:

public class Lock8Demo {
    public static void main(String[] args) throws InterruptedException {
        MyPhone myPhone = new MyPhone();

        new Thread(() -> {
            myPhone.sendEmail();
        }, "线程一").start();

        new Thread(() -> {
            myPhone.hello();
        }, "线程二").start();

    }
}

在本例中,会先执行hello,没有加synchronized的普通方法,不会加锁。

5.第四锁,两步手机会先打印邮件还是短信
public class Lock8Demo {
    public static void main(String[] args) throws InterruptedException {
        MyPhone myPhone = new MyPhone();
        MyPhone myPhone2 = new MyPhone();
        new Thread(() -> {
            myPhone.sendEmail();
        }, "线程一").start();

        new Thread(() -> {
            myPhone2.sendMS();
        }, "线程二").start();

    }
}

在本例中,会先打印短信。因为两个线程调用的是你两个不同实例的方法,在线程一的方法暂停两秒钟的情况下,先打印短信

6.第五锁,两个静态同步方法,一部手机,请问是先打印邮件还是短信

修改资源类,改变为静态同步方法

class MyPhone {
    public static synchronized void sendEmail() {
        // 发送邮件
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("----sendEmail");
    }

    // 发送短信
    public static synchronized void sendMS() {
        System.out.println("----sendMS");

    }
    // 普通方法hello
    public void hello() {
        System.out.println("----hello");
    }
}

测试代码:

public class Lock8Demo {
    public static void main(String[] args) throws InterruptedException {
        MyPhone myPhone = new MyPhone();
        MyPhone myPhone2 = new MyPhone();
        new Thread(() -> {
            myPhone.sendEmail();
        }, "线程一").start();

        new Thread(() -> {
            myPhone.sendMS();
        }, "线程二").start();

    }
}

在本例中,会先打印邮件。具体原因,我们先看第六锁。

7.第六锁,两个静态同步方法,两步手机,请问是先打印邮件还是短信
public class Lock8Demo {
    public static void main(String[] args) throws InterruptedException {
        MyPhone myPhone = new MyPhone();
        MyPhone myPhone2 = new MyPhone();
        new Thread(() -> {
            myPhone.sendEmail();
        }, "线程一").start();

        new Thread(() -> {
            myPhone2.sendMS();
        }, "线程二").start();

    }
}

在本例中同样会先打印邮件。因为static修饰的方法在JVM中只会有一份,不管实例多少个对象,调用的都是一个方法,一次两个线程即使是两个对象,但其实相当于是一个类,会是允许一个线程进入,所以会先打印邮件,因此第五锁和第六锁同样的效果。

8.第七锁,一个普通同步方法,一个静态同步方法,一部手机,请问是先打印邮件还是短信

修改资源类

class MyPhone {

    public static synchronized void sendEmail() {
        // 发送邮件
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("----sendEmail");
    }

    // 发送短信
    public synchronized void sendMS() {
        System.out.println("----sendMS");

    }

    // 普通方法hello
    public void hello() {
        System.out.println("----hello");
    }
}

测试代码:

public class Lock8Demo {
    public static void main(String[] args) throws InterruptedException {
        MyPhone myPhone = new MyPhone();
        MyPhone myPhone2 = new MyPhone();
        new Thread(() -> {
            myPhone.sendEmail();
        }, "线程一").start();

        new Thread(() -> {
            myPhone.sendMS();
        }, "线程二").start();

    }
}

在当前例子中,会先打印短信。因为线程一的静态方法锁的是当前类,而线程二锁的是当前实例对象,就相当于是两个不同的类,因此线程二会先执行。

9.一个普通同步方法,一个静态同步方法,两步手机,请问是先打印邮件还是短信

测试代码:

public class Lock8Demo {
    public static void main(String[] args) throws InterruptedException {
        MyPhone myPhone = new MyPhone();
        MyPhone myPhone2 = new MyPhone();
        new Thread(() -> {
            myPhone.sendEmail();
        }, "线程一").start();

        new Thread(() -> {
            myPhone2.sendMS();
        }, "线程二").start();

    }
}

在本例中,先打印短信即线程二会先执行,原理同第七锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值