首先要明确,wait是Object类的方法,也就是说,所有的对象都有wait方法,而且都是Object中的wait方法因为wait方法被标为final无法被重写,源码如下:
- public final native void wait(long timeout) throws InterruptedException;
native关键字修饰,表示这个方法使用其他语言实现,又由java由C编写可得,这个方法做了很可能是C与操作系统级别的交互。抛出InterruptedException,表示线程可能由已经终止的风险。
Object提供了几个wait方法:
最终都调用了我上面贴了源码的那个方法。这里wait由两个参数的方法需要解释一下,一个long类型参数表示的就是线程等待时间,第二个int类型参数nanos表示纳秒,1毫秒=1000微秒=1000000纳秒。当参数nanos超过500000时,等待的毫秒值也就是timeout++,源码如下:
- public final void wait(long timeout, int nanos) throws InterruptedException {
- if (timeout < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
- if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
- timeout++;
- }
- wait(timeout);
- }
说是为wait方法提供了更加精准的时间控制,但是这个也略敷衍了吧。处理方法明白说 - 就是大于半毫秒的+1毫秒,小于半毫秒的直接舍弃。
说完wait的源码,看一下停止wait的方法,notify和notifyAll。
与wait一样,notify和notifyAll也是Object提供的方法,也是native方法。
两者的区别就在这个All上,下面详细介绍一下:
1.notify :随机 (据说与线程优先级有关) 唤醒一个登记集中的等待线程,该线程将从等待集中移除,重新加入对CPU时间片的竞争当中。
2.notifyAll:唤起所有等待集中的等待线程,所有都加入对CPU时间片的争夺中,先抢到锁的先执行。
wait和notify和notifyAll的使用场景:
已知wait有释放同步锁的效果,即当处于synchronized方法中的线程进入wait后,synchronized锁将会自动被释放,其他线程可以申请锁、持有锁,然后进入这个synchronized方法进行运行。
notify和notifyAll后并不会返回之前持有的锁,而是一起开始竞争锁,谁先竞争到了,谁先执行。
接下来说一下sleep方法,这个方式是由Thread提供的native方法,与wait一样,抛出了InterruptedException异常:
- /**
- * Causes the currently executing thread to sleep (temporarily cease
- * execution) for the specified number of milliseconds, subject to
- * the precision and accuracy of system timers and schedulers. The thread
- * does not lose ownership of any monitors.
- *
- * @param millis
- * the length of time to sleep in milliseconds
- *
- * @throws IllegalArgumentException
- * if the value of {@code millis} is negative
- *
- * @throws InterruptedException
- * if any thread has interrupted the current thread. The
- * <i>interrupted status</i> of the current thread is
- * cleared when this exception is thrown.
- */
- public static native void sleep(long millis) throws InterruptedException;
- /**
- * Causes the currently executing thread to sleep (temporarily cease
- * execution) for the specified number of milliseconds plus the specified
- * number of nanoseconds, subject to the precision and accuracy of system
- * timers and schedulers. The thread does not lose ownership of any
- * monitors.
- *
- * @param millis
- * the length of time to sleep in milliseconds
- *
- * @param nanos
- * {@code 0-999999} additional nanoseconds to sleep
- *
- * @throws IllegalArgumentException
- * if the value of {@code millis} is negative, or the value of
- * {@code nanos} is not in the range {@code 0-999999}
- *
- * @throws InterruptedException
- * if any thread has interrupted the current thread. The
- * <i>interrupted status</i> of the current thread is
- * cleared when this exception is thrown.
- */
- public static void sleep(long millis, int nanos)
- throws InterruptedException {
- if (millis < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
- if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
- millis++;
- }
- sleep(millis);
- }
PS:双参数的sleep与双参数的wait方法一样,提供了更加精细(然而并没有)的时间控制,上面说了就不重复一遍了。
sleep与wait,在非多线程运行条件下的情况是一样的,都是当前线程让出执行机会,进入休眠/等待。但是在synchronized中就有一些不一样了:
1.wait会释放同步锁,让其他线程进入synchronized代码块执行。sleep不会释放锁,其他线程只能等待在synchronized代码块中进入sleep的线程醒后执行完毕才能竞争持有锁。
2.wait可以被notify/notifyAll等方法唤醒,继续竞争CPU和锁。sleep方法只能等待线程睡眠时间到继续运行。
wait和notify/notifyAll以及sleep的测试代码:
待补充