sleep() 方法使当前线程进入停滞状态(阻塞当前线程),让出 CUP 的使用,目的是不让当前线程独自霸占该进程所获的 CPU 资源。该方法是 Thread 类的静态方法,当在一个 synchronized 块中调用 sleep() 方法时,线程虽然休眠了,但是其占用的锁并没有被释放;当 sleep() 休眠时间期满后,该线程不一定会立即执行,因为其它线程可能正在运行而且没有被调度为放弃执行,除非此线程具有更高的优先级。
wait() 方法是 Object 类的,当一个线程执行到 wait() 方法时就进入到一个和该对象相关的等待池中,同时释放对象的锁(对于 wait(long timeout) 方法来说是暂时释放锁,因为超时时间到后还需要返还对象锁),其他线程可以访问。wait() 使用 notify() 或 notifyAll() 或者指定睡眠时间来唤醒当前等待池中的线程。wait() 必须放在 synchronized 块中使用,否则会在运行时抛出 IllegalMonitorStateException 异常。
由此可以看出它们之间的区别如下:
- sleep() 不释放同步锁,wait() 释放同步锁。
- sleep(milliseconds) 可以用时间指定来使他自动醒过来,如果时间没到则只能调用 interreput() 方法来强行打断(不建议,会抛出 InterruptedException),而 wait() 可以用 notify() 直接唤起。
- sleep() 是 Thread 的静态方法,而 wait() 是 Object 的方法。
- wait()、notify()、notifyAll() 方法只能在同步控制方法或者同步控制块里面使用,而 sleep() 方法可以在任何地方使用。
sleep()和yield()方法的区别
(1)sleep() 方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;而 yield() 方法只会给相同优先级或更高优先级的线程以运行的机会,甚至可能会是自己继续得到运行机会。
(2)线程执行 sleep() 方法后转入阻塞(blocked)状态,而执行 yield() 方法后转入就绪(ready)状态。
(3)sleep() 方法声明抛出 InterruptedException,而 yield() 方法没有声明任何异常。
join()和yield()方法的区别
join() 方法的作用是让 “主线程” 等待 “子线程” 结束之后才能继续运行。
yield() 方法的作用是可以暂停当前正在执行的线程对象,让其它有相同优先级的线程执行。它是一个静态方法而且只保证当前线程放弃 CPU 占用而不能保证使其它线程一定能占用 CPU,执行 yield() 的线程有可能在进入到暂停状态后马上又被执行。
锁池:
锁池的本质就是假设线程 A 已经拥有了某个对象(不是类)的锁,而其它线程 B、C 想要调用这个对象的某个 synchronized 方法(或者块),由于这些 B、C 线程在进入对象的 synchronized 方法(或者块)之前必须先获得该对象锁的拥有权,而恰巧该对象的锁目前正被线程 A 所拥有,所以这些 B、C 线程就进入了该对象的锁池,这就是锁池。
等待池:
等待池的本质就是假设线程 A 调用了某个对象的 wait() 方法,线程 A 就会释放该对象的锁(因为 wait() 方法必须在 synchronized中使用,所以执行 wait() 方法前线程 A 已经持有了该对象的锁),同时线程 A 就进入到了该对象的等待池中。如果此时线程 B 调用了相同对象的 notifyAll() 方法,则处于该对象等待池中的线程就会全部进入该对象的锁池中去准备争夺锁的拥有权。而如果此时线程 B 调用的是相同对象的 notify() 方法,则仅仅会有一个处于该对象等待池中的线程(随机)进入该对象的锁池中去准备争夺锁的拥有权。
notify和notifyAll的区别
当一个线程调用了某个对象的 wait() 方法后就必须等其他线程调用这个对象的 notify/notifyall 方法;使用 notifyall 方法可以唤醒所有处于等待状态的线程,然后使其重新进入锁的争夺队列中,而使用 notify 方法只能唤醒处于等待状态的线程之一;此外如果使用 notify 不当很容易会导致并发死锁出现。
notifyAll 会让对象所有处于等待池的线程全部进入锁池去准备竞争获取一个锁的机会,没有获取到锁而已经呆在锁池的线程只能继续等待其他机会获取锁,而不能再主动回到等待池。对于 notify 来说只会让对象所有等待池中一个随机的线程进入锁池去竞争获取一个锁的机会。