java sleep和wait的区别?
-
sleep是Thread类的方法,wait是Object类中的方法,尽管这这两个方法都会影响线程的状态,但是本质上是有区别的。
-
Thread.sleep不会导致锁行为的改变,如果当前线程是有锁的,那么sleep是不会让出锁的。
-
sleep和wait都会暂停当前的线程,对于CPU资源来说,不管这两种哪种方式暂停的线程,都表示它暂时不需要CPU的执行时间。这时候OS会将执行时间分配给其它线程。区别是,调用wait之后,需要别的线程执行notify或者notifyAll才能使其重新获取CPU的执行时间。
-
Sleep不释放锁,线程是进入阻塞状态,确切的说是TIMED_WAITING。
-
Java的synchronized -- wait的结构,即“获取锁-判断-判断不满足就释放锁-然后等通知重来”,用特定的代码形式来实现“条件同步”:
synchronized { // 获取锁
while (判定条件) wait(); // 如果条件不满足就释放锁,并且等着
// ... 要进入的代码
notify(); // 或者notifyAll,通知其他wait者可以重来
}
如果不写synchronized,就是运行时错误IllegalMonitorStateException;万一忘记了while或者忘记notify,代码正确性就可能有问题,并且连运行时错误都没有。
线程间的状态切换:
- 新建(new):新创建了一个线程对象。
- 可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权。
- 运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
- 阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
- 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
并发编程中常用的几个jdk中的api
- Thread.sleep(long millis) 静态方法。当前线程调用此方法,使当前线程进入阻塞状态(其他阻塞),但不释放任何锁资源,一定时间后线程自动进入runnable状态。给其它线程执行机会的最佳方式.
- obj.wait()或obj.wait(long timeout) 当前线程调用某对象的wait()方法,当前线程释放对象锁(wait一定在synchronized代码块/方法中,故一定得到了锁,才进来的此方法),进入阻塞状态(等待队列)。等待notify或wait设置的timeout到期,方可进入另外一个阻塞状态(锁池)。
- t.join()或t.join(long millis) 非静态方法。当前线程A执行过程中,调用B线程的join方法,使当前线程进入阻塞状态(其他阻塞),但不释放对象锁,等待B线程执行完后或一定时间millis后,A线程进入runnable状态。
- Thread.yield() 静态方法。当前线程调用此方法,使线程由running态进入runnable态,放弃cpu使用权,让cpu再次选择要执行的线程。 注:实际过程中,yield仅仅是让其它具有同等优先级的runnable线程获取执行权,但并不能保证其它具有同等优先级的线程就一定能获得cpu执行权。因为做出让步的当前线程,可能会被cpu再次选中,进入running状态。yield()不会导致阻塞。
网友评论