Java 线程状态以及 sheep()、wait()、yield() 的区别
4. 阻塞(Bloacked):阻塞状态是线程因为某种原因放弃 CPU 的使用权,暂时停止运行,知道线程进入就绪状态后才能有机会转到运行状态。
阻塞的情况分三种:
等待阻塞:运行的线程执行**wait()**方法,该线程会释放占用的所有资源,JVM 会把该线程放入“等待池中”。进入这个状态后是不能自动唤醒的,必须依靠其他线程调用 notify()或者 notifyAll()方法才能被唤醒。
同步阻塞:运行的线程在获取对象的(synchronized)同步锁时,若该同步锁被其他线程占用,则 JVM 会吧该线程放入“锁池”中。
其他阻塞:通过调用线程的 sleep()或者 join()或发出了 I/O 请求时,线程会进入到阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O 处理完毕时,线程重新回到就绪状态
以上三种阻塞状态请参考上面的 2 个图示来理解。
5. 死亡(Dead):线程执行完了或因异常退出了 run()方法,则该线程结束生命周期。
wait(), notify(), notifyAll()等方法介绍
这三个方法都是定义到 Object 类中,wait 的作用是当当前线程释放它所持有的锁进入等待状态,而 notify 和 notifyAll 则是唤醒当前对象上的等待线程。
notify() ——?唤醒在此对象监视器上等待的单个线程。
notifyAll() ——?唤醒在此对象监视器上等待的所有线程。
wait() ——?让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout) ——?让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout, int nanos) ——?让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。
wait()会使“当前线程”等待,并且会释放到它所占用的“锁标志”,从而使线程所在对象中的其他 synchronized 数据可以被其他线程使用。
waite()和 notify()因为会对对象的“锁标志”进行操作,所以它们必须在 synchronized 函数或 synchronizedblock 中进行调用。如果在 non-synchronized 函数或 non-synchronizedblock 中进行调用,虽然能编译通过,但在运行时会发生 IllegalMonitorStateException 的异常。
负责唤醒等待线程的那个线程(我们称为“唤醒线程”),它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个),并且调用 notify()或 notifyAll()方法之后,才能唤醒等待线程。虽然,等待线程被唤醒;但是,它不能立刻执行,因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”之后,等待线程才能获取到“对象的同步锁”进而继续运行。
suspend()和?resume()方法
两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的 resume()被调用,才能使得线程重新进入可执行状态。**典型地,****suspend()和?resume()?被用在等待另一个线程产生的结果的情形:**测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用?resume()使其恢复。
注意区别:
初看起来 wait()?和?notify()?方法与 suspend()和?resume()?方法对没有什么分别,但是事实上它们是截然不同的。区别的核心在于,前面叙述的 suspend()及其它所有方法在线程阻塞时都不会释放占用的锁(如果占用了的话),而 wait()?和?notify()?这一对方法则相反。
sleep() 和 yield()方法
这两个方法都定义在 Thread.java 中
sleep()的作用是让当前线程休眠(正在执行的线程主动让出 cpu,然后 cpu 就可以去执行其他任务),即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。sleep()会指定休眠时间,线程休眠的时候会大于或者等于该休眠时间,当时间过后该线程重新被会形式,他会由“阻塞状态”编程“就绪状态”,从而等待 cpu 的调度执行,注意:sleep 方法只是让出了 cpu 的执行权,并不会释放同步资源锁。
yield()的作用是让步,它能够让当前线程从“运行状态”进入到“就绪状态”,从而让其他等待线程获取执行权,但是不能保证在当前线程调用 yield()之后,其他线程就一定能获得执行权,也有可能是当前线程又回到“运行状态”继续运行,注意:这里我将上面的“具有相同优先级”的线程直接改为了线程,很多资料都写的是让具有相同优先级的线程开始竞争,但其实不是这样的,优先级低的线程在拿到 cpu 执行权后也是可以执行,只不过优先级高的线程拿到 cpu 执行权的概率比较大而已,并不是一定能拿到。
举个例子:一帮朋友在排队上公交车,轮到 Yield 的时候,他突然说:我不想先上去了,咱们大家来竞赛上公交车。然后所有人就一块冲向公交车,
有可能是其他人先上车了,也有可能是 Yield 先上车了。
但是线程是有优先级的,优先级越高的人,就一定能第一个上车吗?这是不一定的,优先级高的人仅仅只是第一个上车的概率大了一点而已,
最终第一个上车的,也有可能是优先级最低的人。并且所谓的优先级执行,是在大量执行次数中才能体现出来的。
wait 和 sleep 的区别
相同点:
1. 他们都是在多线程的环境下,都可以在程序的调用出阻塞指定的毫秒数并且返回
2. 两个方法都可以通过 interrupt()方法打断线程的暂停状态,但是线程会抛出 InterruptedException。需要注意的是,InterruptedException 是线程自己从内部抛出的,并不是 interrupt()方法抛出的。对某一线程调用 interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出 Int
erruptedException。但是,一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出 InterruptedException 。?
不同点:
1. Thread 类的方法:sleep(),yield()
Object 的方法:wait()和 notify()、notifyAll()
2. 每个对象都有一个锁来控制同步访问。Synchronized 关键字可以和对象的锁交互,来实现线程的同步。?sleep 方法没有释放锁,而 wait 方法释放了锁,使得其他线程可以使用同步控制块或者方法。?
评论