8锁问题

背景:对于一个资源类,涉及了两个方法,如下:

class phone{
        public synchronized void sendMail(){
               System.out.println("发邮件~");
        }
        public synchronized void call(){
            System.out.println("打电话~");
        }
    }

使用两个线程操纵资源类:

public static void main(String[] args)  {
        phone phone = new phone();
        new Thread(()->{
            phone.sendMail();
            },"A").start();
          }
        new Thread(()->{phone.call();},"B").start();
    }
第一种情况:两个线程操纵资源类中的两个方法,执行结果:发邮件~

打电话~

第二种情况,在第一个方法上加上延时:
public static void main(String[] args)  {
        phone phone = new phone();
        new Thread(()->{
            phone.sendMail();
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            },"A").start();

        new Thread(()->{phone.call();},"B").start();
    }
    
     class phone{
        public synchronized void sendMail(){
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("发邮件~");
        }

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

结果输出:

发邮件~
打电话~

分析以上两种情况:
两个方法都被synchronized关键字修饰,被修饰的方法的锁是当前方法的调用者;由于main方法中只有一个对象phone,所以在调用两个方法时使用的是同一把锁,一次只能执行该对象的一个方法,谁先拿到锁谁先执行,跟是否sleep无关,因为sleep并不释放锁。

第三种情况,在phone类中再增加一个普通方法,非 ynchronized;

在main方法中调用phone.hello,最终的执行结果为:

hello
发邮件~
  • 原因在于hello未使用synchronized关键字修饰,是普通方法,不受锁的影响。
第四种情况:对于两个对象phone1,phone2,分别调用两个方法phone1.sendmail(),phone2.sendmail()—》
phone phone1 = new phone();
phone phone2 = new phone();
new Thread(()->{phone2.call();},"B").start();
new Thread(()->{phone1.sendMail();},"A").start();

执行的顺序为:

打电话~
Disconnected from the target VM, address: '127.0.0.1:11629', transport: 'socket'
发邮件~

原因在于,phone1和phone2是两个对象,两把锁,互不影响,由于sendMail方法sleep了4秒,因此call方法先执行;

第五种情况:在两个方法上加static关键字,一个phone对象
public static synchronized void sendMail(){
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发邮件~");
    }
    public static synchronized void call(){
        System.out.println("打电话~");
    }

执行结果:

打电话~
发邮件~

原因:synchronized关键字加在静态方法上,当前锁对象是Class对象,该对象全局唯一,因此两个方法使用的是同一把锁,由于sendMail方法有延迟因此后执行;

第六种情况:加上普通方法hello(),两个对象

执行结果为:

hello!
发邮件~
打电话~

分析:hello方法总是最先执行,因为不需要锁;call()方法和sendMail()方法执行情况同五,因为不论是几个对象,锁的仍然是Class对象,因此执行顺序是谁先获得锁谁先执行;

第七种情况:一个修饰静态方法,一个修饰实例方法,一个对象;
 phone3 p3 = new phone3();
new Thread(()->{p3.hello();},"C").start();
new Thread(()->{p3.sendMail();},"A").start();
new Thread(()->{p3.call();},"B").start();

执行结果

hello!
打电话~
发邮件~

分析:两个方法是两把锁,call()方法不需要等待sendMail()的锁;

第八种情况:一个修饰静态方法,一个修饰实例方法,两个对象;

结果:

hello!
打电话~
发邮件~

原因:两个方法是不同的锁,与对象的个数无关;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值