1
1
## wait()和sleep()的区别
2
2
3
3
### 问题:
4
- 在线程里` wait() ` 和` sleep() ` 的区别?
5
- 我的理解是一条` wait() ` 线程语句后,仍然在运行这个模块,并且占用CPU,但是一条` sleep() ` 语句并不会占用CPU,对吗?
6
- 为什么需要` sleep() ` 和` wait() ` 两条语句:他们在底层是怎么执行的?
4
+ 在线程里 ` wait() ` 和 ` sleep() ` 的区别?
5
+
6
+ 我的理解是执行 ` wait() ` 语句后,该线程仍是运行态,并且会占用CPU,但是执行 ` sleep() ` 后,该线程则不会占用CPU,对吗?
7
+
8
+ 为什么需要 ` sleep() ` 和 ` wait() ` 两条语句:他们底层是如何实现的?
7
9
8
10
### 回答:
9
- [ ` wait ` ] ( http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#wait%28%29 ) 可以被另一个进程唤醒通过调用 [ ` notify ` ] ( http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notify%28%29 ) 而 ` sleep ` 不行。并且 ` wait ` 和 ` notify ` 必须在监控对象同步块内发生而 ` sleep ` 不行。
11
+ 线程 在 [ ` wait ` ] ( http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#wait%28%29 ) 后,可以被另一个拥有相同 ` synchronized ` 对象的线程,通过调用 [ ` notify ` ] ( http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notify%28%29 ) 唤醒,而 ` sleep ` 不行。` wait ` 和 ` notify ` 能正常执行的条件是(否则会抛异常):多个线程的代码,都包在 ` synchronized ` 块中,并且 ` synchronized ` 锁的对象需要是同一个。如下所示:
10
12
```
11
13
Object mon = ...;
12
14
synchronized (mon) {
13
15
mon.wait();
14
16
}
15
17
```
16
- 在此刻正在执行的线程 ` wait ` 后释放了监视器。另外一个线程可能在做
18
+ 上面这个线程调用了 ` wait ` 后,会进入等待状态。这时另外一个线程可以这样做:
17
19
```
18
20
synchronized (mon) { mon.notify(); }
19
21
```
20
- (同一个` mon ` 对象)第一个线程(假设它是唯一在监视器上等待的线程)将会唤醒。
21
- 如果有很多的线程在等待你可以调用[ ` notifyall ` ] ( http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notifyAll%28%29 ) 来唤醒。但是只有其中之一能抢夺到该对象的监视器并继续执行(` wait ` 是在` synchronized ` 块内)。其他的线程会被锁住直到他们获得监视器的锁。
22
- 另外就是你可以` wait ` 对象本身(例如:你可以` wait ` 一个对象的监视器)但是你只能` sleep ` 线程。
23
- 另外还有你可能会得到伪唤醒(例如:等待的线程没有任何操作就唤醒了)
24
- 如果你按照下面的做法,你就能一直处于等待的状态尽管出现一些原因使他唤醒了。
22
+ 可以看到,` synchronized ` 锁对象,都是mon。因此,当第二个线程调用了 ` notify() ` 方法,第一个线程就会唤醒(假设有且仅有一个线程是被包在 ` synchronized (mon) ` 中且处于等待状态)。
23
+
24
+ 如果有多个线程在等待(且` synchronized ` 锁对象是同一个,如上例中的mon),则可以调用[ ` notifyAll ` ] ( http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notifyAll%28%29 ) 来唤醒。但是,只有其中一个线程能抢到锁并继续执行(因为 ` wait ` 的线程都是在 ` synchronized ` 块内,需要争夺 ` synchronized ` 锁)。其他的线程会被锁住,直到他们依次获得锁。
25
+
26
+ 再补充几点:
27
+ 1 . ` wait ` 方法由 ` Object ` 对象调用(例如:你可以让 ` synchronized ` 锁对象调用 ` wait ` ,如上面例子的mon.wait()),而 ` sleep ` 则由线程调用。
28
+
29
+ 2 . ` wait ` 之后,可能会伪唤醒(` spurious wakeups ` )(正在waiting的线程,无故就被唤醒了,如遇到interrupted, timing out等情况)。因此,你需要多设置一些检查,如果不满足实际的运行条件,则继续等待,如下:
25
30
```
26
31
synchronized {
27
32
while (!condition) { mon.wait(); }
28
33
}
29
34
```
30
- (wait前会释放监视器,被唤醒后又要重新获取,这瞬间可能有其他线程刚好先获取到了监视器,从而导致状态发生了变化, 这时候用while循环来再判断一下条件(比如队列是否为空)来避免不必要或有问题的操作。)
35
+
36
+ 3 . 当线程调用 ` sleep ` 时,并没有释放对象锁,而 ` wait ` 则释放了对象锁:
37
+ ```
38
+ synchronized(LOCK) {
39
+ Thread.sleep(1000); // LOCK is held
40
+ }
41
+ synchronized(LOCK) {
42
+ LOCK.wait(); // LOCK is not held
43
+ }
44
+ ```
45
+
46
+ 最后,再小结一下:
47
+ - ` sleep() ` :“我已经完成了一个时间片,** 在n微秒** 前,请不要再给我一个时间片”。这时操作系统不会让这个线程做任何事情,直到sleep时间结束。
48
+ - ` wait() ` :"我已经完成了一个时间片,** 在其他线程调用` notify() ` 前** ,请不要再给我一个时间片)。这时操作系统不会安排这个线程继续运行,直到有人调用了` notify() `
49
+
50
+
31
51
32
52
** stackoverflow链接:**
33
53
http://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep
@@ -36,3 +56,4 @@ http://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep
36
56
37
57
1 . [ Java: notify() vs. notifyAll() all over again] ( http://stackoverflow.com/questions/37026/java-notify-vs-notifyall-all-over-again )
38
58
2 . [ 线程通信] ( http://ifeve.com/thread-signaling/ )
59
+ 3 . [ 最简实例说明wait、notify、notifyAll的使用方法] ( http://longdick.iteye.com/blog/453615 )
0 commit comments