为什么wait()要在synchronized块中执行

一、不在synchronized块中执行的话,虽然编译时会通过,但在运行的过程中会报错IllegalMonitorStateException。

二、从逻辑上分析:

        wait()、notify()、notiryAll()这种等待唤醒机制是为了实现线程之间的同步,而实现同步的话,在大多数情况下是建立在互斥的基础上的,就这种情况来说,如果不加同步锁(synchronized)实现互斥的话,有可能会发生下面这种情乱:

        wait() 方法还没有执行完,notify() / notifyAll() 方法已经执行完,这样 notify() / notifyAll() 就进行了一次空唤醒操作,而 wait() 执行完后由于再没有notify() / notifyAll()的唤醒,会导致wait() 所在线程一直阻塞。

三、从底层实现分析:

        既然要保证 wait()、notify()、notiryAll() 和互斥性,为什么不用 ReentrantLock 这种可重入锁来实现互斥配合呢?

        首先,每个Java对象底层都会关联一个 Monitor 对象,在 Monitor 中维护了 两个队列 WaitSet 和 EntryList ,owner 属性。

        ReentrantLock 它实现互斥是通过用cas对 AQS同步器中 state 属性进行操作,以及park()/unpark()来实现互斥。而 synchronized( lock ) 被调用后会将当前线程 赋值给lock对象所关联的 monitor 对象的 owner 属性,其他线程 再想获取 lock 锁对象的话如果发现  lock对象所关联的 monitor 对象的 owner 属性不为空,就会进入 EntryList 进行阻塞,而调用了wait() 后就会将 owner 指向的线程对象放入 WaitSet 中进行等待,并将 owner 置为 null (释放掉锁),直到其他线程获取到 lock 这个对象锁以后通过 notify() / notifyAll() 方法 唤醒 WaitSet 中 的线程,这时 WaitSet中等待的线程才会进入 EntryList 参与lock 锁的竞争。( notify() / notifyAll() 并不会释放锁,只有等待 synchronized 执行完才会释放锁 )

        ReentrantLock它实现同步/互斥并不会涉及到 monitor,所以 不能用 ReentrantLock 这种可重入锁来实现互斥配合 wait()、notify()、notiryAll()。

以上个人理解,若有不对之处请指正

你可能感兴趣的:(java,开发语言,juc)