java多线程8锁问题

java 8锁问题

一个类,里面有静态同步方法、普通同步方法、普通方法等,通过分析不同对象、不同线程,确定锁的是谁

1.标准情况下,一个对象,两个线程
public class Test01 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        //线程A
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        //加个延迟,确保线程A先拿到锁
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
		//线程B
        new Thread(()->{
            phone.call();
        },"B").start();
    }
}

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

先执行发短信还是先执行打电话?

答案:先执行打印发短信。因为此时synchronized锁的是方法的调用者,虽然有两个线程,但是是一个对象,一个锁,线程A拿到锁之后,如果不释放,线程B就无法获得锁。

2.sendSms方法延迟4秒,一个对象,两个线程
public class Test01 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        //线程A
        new Thread(()->{
            phone.sendSms();
        },"A").start();
		//加个延迟,确保线程A先拿到锁
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //线程B
        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("打电话");
    }
}

先打印发短信还是打电话?

答案:先执行打印发短信。和上面一样,两个线程同一把锁,线程B要等线程A将锁释放

3.将打电话修改为普通方法(不是同步方法),一个对象,两个线程
public class Test02 {
    public static void main(String[] args) {
        Phone phone1 = new Phone();

        //线程A
        new Thread(()->{
            phone.sendSms();
        },"A").start();
		//加个延迟,确保线程A先开始
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
		//线程B
        new Thread(()->{
            phone.call();
        },"B").start();
    }
}

class Phone{
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);//延时四秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    //这里没有锁,不是同步方法
    public void call(){
        System.out.println("打电话");
    }
}

先执行发短信还是打电话?

答案:打电话。因为线程A虽然先开始而且拿到锁,但是执行sendSms方法,有四秒的延迟,而线程B执行的不是同步方法,不需要等待线程A释放锁,所以会在线程A的四秒延迟结束之前执行完。(锁的还是对象)

4.两个对象,两个线程,两个同步方法
public class Test02 {
    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        //线程A
        new Thread(()->{
            phone1.sendSms();
        },"A").start();
		//加个延迟,确保线程A先开始
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
		//线程B
        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}

class Phone{
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");//延时四秒
    }
    public synchronized void call(){
        System.out.println("打电话");
    }

}

先执行发短信还是打电话?

答案:打电话。因为线程A虽然先开始而且拿到锁,但是执行sendSms方法,有四秒的延迟,而线程B与线程A不是同一个对象,不需要等待线程A释放锁,所以会在线程A的四秒延迟结束之前执行完先打印。(锁的是方法的调用者,两个对象两个锁)

5.一个对象,两个线程,两个静态同步方法
public class Test01 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        //线程A
        new Thread(()->{
            phone.sendSms();
        },"A").start();
		//加个延迟,确保线程A先拿到锁
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //线程B
        new Thread(()->{
            phone.call();
        },"B").start();
    }
}

class Phone{
    //静态方法,类一加载就有了,所以静态同步方法锁的是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("打电话");
    }
}

先执行发短信还是打电话?

答案:发短信。因为静态同步方法锁的是Class类,两个线程同一把锁,A先拿到锁之后,B要等A执行完释放锁

6.两个对象,两个线程,两个静态同步方法
public class Test01 {
    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        //线程A
        new Thread(()->{
            phone1.sendSms();
        },"A").start();
		//加个延迟,确保线程A先拿到锁
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //线程B
        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}

class Phone{
    //静态方法,类一加载就有了,所以静态同步方法锁的是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("打电话");
    }
}

先执行发短信还是打电话?

答案:发短信。和上面原因一样,静态同步方法锁的是Class类,虽然两个线程中是两个不同的对象,但是Class是唯一的。所以两个线程还是同一把锁,A先拿到锁之后,B要等A执行完释放锁。

$$

$$

7.一个对象,两个线程,一个静态同步方法,一个普通同步方法
public class Test01 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        //线程A
        new Thread(()->{
            phone.sendSms();
        },"A").start();
		//加个延迟,确保线程A先拿到锁
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //线程B
        new Thread(()->{
            phone.call();
        },"B").start();
    }
}

class Phone{
    //静态方法,类一加载就有了,所以静态同步方法锁的是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("打电话");
    }
}

先执行发短信还是打电话?

答案:打电话。因为第一个锁的是Class,第二个锁的是方法的调用者,也就是new出来的对象。所以两个线程中虽然是同一个对象,但是需要的不是同一把锁,所以线程B不需要等待线程A释放锁。而线程A有四秒延迟,所以先打印打电话。

8.两个对象,两个线程,一个静态同步方法,一个普通同步方法
public class Test01 {
    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();

        //线程A
        new Thread(()->{
            phone1.sendSms();
        },"A").start();
		//加个延迟,确保线程A先拿到锁
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //线程B
        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}

class Phone{
    //静态方法,类一加载就有了,所以静态同步方法锁的是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("打电话");
    }
}

先执行发短信还是打电话?

答案:打电话。元音和上面一题一样,两个线程中需要的不是同一把锁,所以线程B不需要等待线程A释放锁。而线程A有四秒延迟,所以先打印打电话。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值