等待通知机制
之前所学到的join是等待线程结束,而此时的等待通知,等待代码给我们提示进行显示的通知(并不一定要结束),可以更加精细控制线程之间的执行顺序,在系统内部,线程是抢占式执行,随机调度,但是程序员也是有手段可以进行干预的,我们可以通过"等待"的方式让线程按照咱们预期来执行,无法主动让某个线程被调度,可以让某个线程被等待.
线程饿死问题
一个线程频繁的获取释放锁,由于获取的太空,以至于其他线程无法获取cpu资源,等待通知机制就可以解决上述机制,通过条件判断,当前逻辑是否能够执行,如果不能执行就主动wait等待(主动进行阻塞),把执行线程的机会让给别的线程,就可以避免一些无意的重试.等到时机成熟了(其他线程的通知)在让阻塞的线程被唤醒.
关于wait()和notify()方法
wait是Object所提供的方法,所以的类都会有这个方法
wait和sleep一样都是会被Interrupt打断,也能够自动清除标志位,也有超时间就会自动唤醒,不会死等
这个报错提示中的Monitor指的就是synchronized,其在jvm中涉及的术语就是monitor(也叫监视器锁)
wait内部做的事情不仅仅是阻塞等待,还要解锁,准确来说是解锁同时进行等待,然后解锁的前提是加锁,所以wait必须放在synchronized里面使用
此时就会成功阻塞等待,当执行到wait操作时,在wait内部会先解锁,此时object这个锁其他线程是可以获取到的,wait释放锁之后会休息自己不参与调度,把机会让给别人,什么时候开始执行,此时就需要notify()方法,跟wait()配合使用,其他线程通过使用notify将wait唤醒,使用notify的线程必须跟使用wait的线程锁是同一把锁.
t2把t1唤醒之后,并不能立即执行,t1需要重新获取锁,由于此时t2还没有结束,t1无法获取到锁被阻塞,所以需要等到t2释放锁以后,t1才能继续执行
t2执行notify之后会将wait()唤醒,此时t1的线程从WAITING->RUNNABLE,,但是由于t2还没有将锁释放,而t1t2都是同一把锁,所以t1状态变为BLOCK,等到t2的代码块执行完毕以后,t1的线程状态变为RUNNABLE,在执行线程中的内容,所以此时会看到t2先执行完才执行t1
如果此时先执行t2然后在sleep一下,t1就会阻塞等待,因为当t2执行完notify之后,t1执行wait之后没有方法可以将其唤醒,所以会阻塞等待
多线程代码总是充满随机性,只要代码变了一点,就会充满不同,notify()只可以随机唤醒一个线程,如果要准确对应唤醒线程,必须确保notify和wait的锁对象是一样的,这样就可以准确的唤醒.notifyAll()该方法可以唤醒所有wait()线程前提是跟这个方法锁对象一样的