首先要明确,wait是Object类的方法,也就是说,所有的对象都有wait方法,而且都是Object中的wait方法
因为wait方法被标为final无法被重写,源码如下:
public final native void wait(long timeout) throws InterruptedException;
== native关键字修饰,表示这个方法使用其他语言实现==,又由java由C编写可得,这个方法做了很可能是C与操作系统级别的交互。
抛出InterruptedException,表示线程可能由已经终止的风险。
最终都调用了我上面贴了源码的那个方法。
这里wait由两个参数的方法需要解释一下,
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方法提供了更加精准的时间控制,但是这个也略敷衍了吧。
说完wait的源码,看一下停止wait的方法,notify和notifyAll。
两者的区别就在这个All上,下面详细介绍一下:
notify :随机 (据说与线程优先级有关) 唤醒一个登记集中的等待线程,该线程将从等待集中移除,重新加入对CPU时间片的竞争当中。
notifyAll:唤起所有等待集中的等待线程,所有都加入对CPU时间片的争夺中,先抢到锁的先执行。
wait和notify和notifyAll的使用场景:
已知wait有释放同步锁的效果,即当处于synchronized方法中的线程进入wait后,synchronized锁将会自动被释放,其他线程可以申请锁、持有锁,然后进入这个synchronized方法进行运行。
notify和notifyAll后并不会返回之前持有的锁,而是一起开始竞争锁,谁先竞争到了,谁先执行。
package cn.edut.com.test;
public class Test_Thread {
static Object obj = new Object() ;
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.start();
Thread.sleep(1000);
// synchronized(obj) {
// obj.notifyAll();
// }
t.interrupt();
}
static class T extends Thread {
@Override
public void run() {
synchronized (obj) {
try {
long start = System.currentTimeMillis();
obj.wait(10000);
long end = System.currentTimeMillis();
System.out.println("等待了"+(end-start)/1000+"秒");
} catch (InterruptedException e) {
System.out.println("Interrupted !!!!");
e.printStackTrace();
}
}
}
}
}
package cn.edut.com.test;
public class Test_Thread {
static Object obj = new Object() ;
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.start();
Thread.sleep(1000);
synchronized(obj) {
obj.notifyAll();
}
//t.interrupt();
}
static class T extends Thread {
@Override
public void run() {
synchronized (obj) {
try {
long start = System.currentTimeMillis();
obj.wait(10000);
long end = System.currentTimeMillis();
System.out.println("等待了"+(end-start)/1000+"秒");
} catch (InterruptedException e) {
System.out.println("Interrupted !!!!");
e.printStackTrace();
}
}
}
}
}
接下来说一下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
* interrupted status 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
* interrupted status 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方法一样,提供了更加精细(然而并没有)的时间控制,上面说了就不重复一遍了。
package cn.edut.com.test;
public class Test_Thread {
public static void main(String[] args) {
T t = new T();
t.start();
//t.notify();//无法用notify唤醒
t.interrupt();
}
}
class T extends Thread {
@Override
public void run() {
try {
sleep(3000);
System.out.println("没有打断");
} catch (InterruptedException e) {
System.out.println("这里!!!");
e.printStackTrace();
}
}
}
无法唤醒,该等3秒,还是等了三秒
package cn.edut.com.test;
public class Test_Thread1 {
public static void main(String[] args) {
T t = new T();
t.start();
synchronized(t ) {
t.notifyAll();//无法用notify唤醒
}
//t.interrupt();
}
}
class T extends Thread {
@Override
public void run() {
try {
long start = System.currentTimeMillis();
sleep(3000);
long end = System.currentTimeMillis();
System.out.println("等待:"+ (end - start)/1000 +"秒");
} catch (InterruptedException e) {
System.out.println("这里!!!");
e.printStackTrace();
}
}
}
sleep与wait,在非多线程运行条件下的情况是一样的,都是当前线程让出执行机会,进入休眠/等待。
但是在synchronized中就有一些不一样了:
wait会释放同步锁,让其他线程进入synchronized代码块执行。
sleep不会释放锁,其他线程只能等待在synchronized代码块中进入sleep的线程醒后执行完毕才能竞争持有锁。
wait 可以被 notify/notifyAll 等方法唤醒,继续竞争CPU和锁。
sleep方法只能等待线程睡眠时间到,才能继续运行。
方法 | 提供 | 释放锁? | 备注 | 异常 | Iterrupted 情况 | 被唤醒情况 |
---|---|---|---|---|---|---|
wait | Object的final方法 (不能被Override) | 释 放 \color{#ff0011}{释放} 释放!! | 需要用synchronized包围 | InterruptedException | iterrupt() | 等 待 等 待 时 间 结 束 、 n o t i f y ( ) 、 n o t i f y A l l ( ) 唤 醒 ( 需 要 用 s y n c h r o n i z e d 包 围 ) \color{#ff0011}{等待等待时间结束 、notify()、notifyAll() 唤醒(需要用synchronized包围)} 等待等待时间结束、notify()、notifyAll()唤醒(需要用synchronized包围) |
sleep | Thread的静态方法 | 不 \color{#ff0011}{不} 不! | InterruptedException | iterrupt() | 只 能 等 待 等 待 时 间 结 束 \color{#ff0011}{只能 等待等待时间结束} 只能等待等待时间结束 |