3)Blocked是阻塞的意思,例如遇到一个IO操作,此时CPU处于空闲状态,可能会转而把CPU时间片分给其他线程,这时也可以成为“暂停”状态。Blocked状态结束后,进入Runnable状态,等待系统重新分配资源。
出现阻塞的情况大体分为以下5中:
线程调用sleep()方法,主动放弃占用的处理器资源。
线程调用阻塞式IO方法,在该方法返回前,该线程被阻塞。
线程试图获得一个同步监视器,但该同步监视器正在被其他线程所持有。
线程等待某个通知。
线程调用suspend()方法将该线程挂起,此方法容易死锁,尽量避免使用。
4)run()方法运行结束后进入销毁阶段,整个线程执行完毕。
注:每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列。就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程。一个线程被唤醒才会进入就绪队列,等待CPU的调度,反之一个线程被wait后,就会进入阻塞队列,等待下一次唤醒。
当方法wait()被执行完后,锁会被自动释放,但执行完notify()方法后,锁不自动释放。
注:sleep()方法不释放锁,notify()方法执行后,必须方法所在的synchronized代码执行完毕后才释放锁。
当线程呈wait()状态时,调用线程对象的interrupt()方法会出现InterruptedException异常。
注:
1)执行完同步代码块就会释放对象的锁。
2)在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放。
3)在执行同步代码块的过程中,执行了锁所属对象的wait()方法,这个线程就会释放对象锁,而这个线程就会进入线程等待池中,等待被唤醒。
调用notify()一次只随机唤醒一个线程。(前提是这两个线程使用同一个对象锁)。
调用notifyAll()方法会唤醒所有的线程 。(这些线程全都是使用一个对象锁)。
带一个参数的wait(long)方法的功能是等待某一时间内是否有线程对锁进行唤醒,如果超过这个时间就自动唤醒。
注:也可以在long的时间内被其他线程唤醒(这些线程公用一个对象锁)。
如果通知过早可能会打断程序正常的运行逻辑。
若wait等待的条件发生了变化,也容易造成程序逻辑的混乱。
这个是结合到具体的逻辑判断与数据删减的情况才会涉及到。
这里是使用while()判断替换了if()判断解决的问题(但是目前我没想明白为啥。。)
变形一:一生产与一消费——操作值:
生产者:一个专门用来提供服务,并且在服务提供完成后唤醒消费者。
消费者:专门用来消费服务,并且在消费完之后唤醒生产者。
变形二:多生产与多消费——操作值-假死:“假死”的现象就是线程进入了WAITING等待状态,如果全部线程都进入了WAITING状态(死锁),则程序就不再执行任何业务功能了,整个项目呈停止状态。
案例中出现假死的现象是由于仅仅唤醒了同类(生产者唤醒了生产者,消费者唤醒了消费者)的现象大量出现导致的。
变形三:多生产与多消费——操作值:解决上一小节的假死问题的方式是,将notify()方法改为notifyAll()方法,这样就会通知所有的线程,避免出现假死状态。
变形四:一生产与一消费——操作栈: