wait和sleep的区别 面试 wait和notify yield

要深入了解这两个的区别,我们需要先了解线程的两个状态。一个是运行态,一个是冻结态。

1.什么是运行态呢? 即同时具备cpu的执行资格和执行权。也就是说这个线程有权被cpu执行并且此时正在被cpu执行。

2.什么事冻结态? 即同时释放了cpu的执行权和释放了cpu的执行资格,也就是说这个线程既不拥有被cpu的执行的权利,此时也不被cpu执行。

然后我们对执行资格和执行权进行深入的理解。当一个线程start的时候,就说明这个线程具备了执行资格,但是此时cpu不一定在执行这个线程,也就是说不一定拥有cpu的执行权。当线程拥有执行资格但不拥有执行权的时候,这种状态成为线程的临时阻塞状态。

稍微写多一些多线程程序和有基本理解的人现在应该都能理解上面几种概念了吧。

然后下面的cpu资源指的就是cpu的执行权和执行资格。

然后我们回到wait和sleep的区别上来。

很基本的区别:wait是object类的方法,sleep是thread类的方法。

1.wait释放cpu资源,同时释放锁。

2.sleep也释放cpu资源,但不释放锁。


释放cpu资源意味着不参与cpu的调度,即cpu不可能切换到你这个线程去执行,即没有cpu的执行权和执行资格。


先来简单科普一下wait和notify:我们在使用object类的wait,notify,notifyall的时候,我们都是要标识它们所属于的锁的,就是 锁对象.wait 这样的写法,这三个方法必须是在synchronized块里面使用,因为他们就是操作锁的,这里的锁也叫做监视器对象,离开了锁,操作这三个方法就没有意义。当出现synchronized块嵌套时,就必须要清楚地标明到底是哪个锁的wait和notify,不然就会引发混乱。当你直接写wait的时候,默认是调用this.wait.而synchronized默认的锁对象也是this,所以此时不会报错,但是当你synchronized使用的锁对象不是this时,这个时候就得好好注意啦,我的理解是一般都不要拿this当作锁(除非你方法都在一个类里面,而且结构比较简单),这个锁最好创建好以后放在一个接口里面,然后实现该接口然后调用就完事了。当你notifyall是也不会有线程安全问题,因为此时只有一个线程拥有锁对象。

此时我们再来理解一下wait的释放锁。也就是说在调用锁对象的wait方法时,此线程会释放cpu资源,释放锁,即线程不再运行,放到了线程池当中处于冻结状态。然后另一个线程可以获取这个锁,然后再调用这个锁的notify方法,把在线程池中处于冻结状态的对应线程唤醒。重新获取cpu的执行资格和执行权。

wait()方法遇到下面几件事情之一才会返回:

1.其它线程调用了该共享对象的notify()或者notifyall()方法

2.其他线程调用了该线程的interrupt方法,该线程抛出interruptedexception异常返回。


然后看sleep不释放锁是什么意思。

sleep就是把cpu的执行资格和执行权释放出去,不再运行此线程,当定时时间结束再取回cpu资源,参与cpu的调度,获取到cpu资源后就可以继续运行了。而如果sleep时该线程有锁,那么sleep不会释放这个锁,而是把锁带着进入了冻结状态,也就是说其他需要这个锁的线程根本不可能获取到这个锁。也就是说无法执行程序。如果在睡眠期间其他线程调用了这个线程的interrupt方法,那么这个线程也会抛出interruptexception异常返回,这点和wait是一样的。


既然前面都讲了那么多铺垫,那么吧yield也讲了吧。

正常来说,当一个线程把cpu分配给自己的时间片使用完后,线程调度器才会进入下一轮的线程调度,而当一个线程调用了thread类的静态方法yield时,是在告诉线程调度器自己占有的时间片还没有使用完的部分自己不想再使用了,这暗示线程调度器现在可以进行下一轮线程调度了。也就是说,调用yield方法后,马上释放了cpu的执行权,但是依然保留了cpu的执行资格,所以有可能cpu下次进行线程调度还会让这个线程获取到执行权继续执行。

编辑于 2018-11-18 10:57