synchronized

synchronized是可重入锁

synchronized锁的分类

  • 类锁
  • 对象锁

    锁的本质

    如果一份资源需要多个线程同时访问,需要给该资源加锁。加锁之后,可以保证同一时间只能有一 个线程访问该资源。资源可以是一个变量、一个对象或一个文件等

    synchronized锁的原理

    在对象头里,有一块数据叫Mark Word。在64位机器上,Mark Word是8字节(64位)的,这64位
    中有2个重要字段:锁标志位和占用该锁的thread ID。因为不同版本的JVM实现,对象头的数据结构会
    有各种差异

    1、为什么 wait 必须synchronized保护的同步代码中使用

  • 在使用wait()方法时,必须把wait()方法写在synchronized保护的while代码块中,并始终判断执行条件是否满足

  • 如果满足就往下继续执行,如果不满足就执行wait()方法,而在执行wait()方法之前,必须持有对象的monitor锁,也就是通常所说的synchronized锁
  • image.png

    2、为什么wait/notify/notifyAll被定义在Object类中,而sleep定义在Thread类中?

  • 因为java中每个对象都有一把称之为monitor监视器的锁 由于每个对象都可以上锁,这就要求在对象中有一个保存锁信息的位置 这个锁时对象级别的 而非线程级别的 wait/notify/notifyAll也都是锁级别的操作,他们的锁属于对象 所以把他们定义在Object 类中最合适,因为 Object类时所有对象的父类

  • 因为如果 把wait/notify/notifyAll 方法定义在Thread类中,会带来很大的局限性 比如 一个线程可能持有多把锁 以便实现相互配合的复杂逻辑 假设此时 wait 方法定义在Thread类中 如何实现让一个线程持有多把锁呢 又如何明确线程等待的时那把锁呢? 既然我们是让当前线程去等待某个对象锁, 自然应该通过操作对象来实现 而不是操作线程

    3、wati/notify 和sleep方法的异同?

    相同点

  • 他们都可以让线程阻塞

  • 他们都可以响应interrupt中断:在等待的过程中 如果收到中断信号,都可以进行响应,并抛售InterruptedException异常

    不同点

  • wait方法必须在synchronized保护的代码中使用,而sleep 方法并没有这样的要求

  • 在同步代码中执行sleep方法时 并不会释放monitor锁 但执行wait方法时 会主动释放monitor锁
  • sleep方法中会要求必须定义一个时间,时间到期后会主动恢复,而对于没有参数的wait方法而言 意味着永久等待,直到被中断或被唤醒才能恢复 他不会主动恢复
  • wait/notify时Object类的方法 而sleep 是Thread类的方法