Skip to content

Commit 4491d47

Browse files
committed
优化“wait()和sleep()的区别”一文
1 parent 49541e8 commit 4491d47

File tree

1 file changed

+32
-11
lines changed

1 file changed

+32
-11
lines changed
Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,53 @@
11
## wait()和sleep()的区别
22

33
### 问题:
4-
在线程里`wait()``sleep()`的区别?
5-
我的理解是一条`wait()`线程语句后,仍然在运行这个模块,并且占用CPU,但是一条`sleep()`语句并不会占用CPU,对吗?
6-
为什么需要`sleep()``wait()`两条语句:他们在底层是怎么执行的?
4+
在线程里 `wait()``sleep()` 的区别?
5+
6+
我的理解是执行 `wait()` 语句后,该线程仍是运行态,并且会占用CPU,但是执行 `sleep()`后,该线程则不会占用CPU,对吗?
7+
8+
为什么需要 `sleep()``wait()` 两条语句:他们底层是如何实现的?
79

810
### 回答:
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` 锁的对象需要是同一个。如下所示:
1012
```
1113
Object mon = ...;
1214
synchronized (mon) {
1315
mon.wait();
1416
}
1517
```
16-
在此刻正在执行的线程`wait`后释放了监视器。另外一个线程可能在做
18+
上面这个线程调用了 `wait`后,会进入等待状态。这时另外一个线程可以这样做:
1719
```
1820
synchronized (mon) { mon.notify(); }
1921
```
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等情况)。因此,你需要多设置一些检查,如果不满足实际的运行条件,则继续等待,如下:
2530
```
2631
synchronized {
2732
while (!condition) { mon.wait(); }
2833
}
2934
```
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+
3151

3252
**stackoverflow链接:**
3353
http://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep
@@ -36,3 +56,4 @@ http://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep
3656

3757
1. [Java: notify() vs. notifyAll() all over again](http://stackoverflow.com/questions/37026/java-notify-vs-notifyall-all-over-again)
3858
2. [线程通信](http://ifeve.com/thread-signaling/)
59+
3. [最简实例说明wait、notify、notifyAll的使用方法](http://longdick.iteye.com/blog/453615)

0 commit comments

Comments
 (0)