一、区别与联系
1.1、wait(),notify()和notifyAll()都是java.lang.Object的方法,而确实sleep方法是Thread类中的方法,这是为什么呢?
因为wait和notify的本质是基于条件对象的,而且只能由已经获得锁的线程调用。java的每个Object都有一个隐式锁,这个隐式锁关联一个Condition条件对象,线程拿到这个隐式锁(比如进入synchronized代码区域),就可以调用wait,语义是在Condition条件对象上等待,其他的线程可以在这个Condition条件对象上等待,等满足条件之后,就可以调用notify或者notifyAll来唤醒所有在此条件对象上等待的线程。
1.2、sleep() 和 wait() 区别
对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
在调用sleep()方法的过程中,线程不会释放对象锁。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
1.3、notify和notifyAll区别
所有处于wait状态的线程,使其重新进入锁的争夺队列中,而notify只能唤醒一个。注意,任何时候只有一个线程可以获得锁,也就是说只有一个线程可以运行synchronized 中的代码,notifyall只是让处于wait的线程重新拥有锁的争夺权,但是只会有一个获得锁并执行
wait()和notify()是直接隶属于Object类,也就是说,所有对象都拥有这一对方法。初看起来这十分 不可思议,但是实际上却是很自然的,因为这一对方法阻塞时要释放占用的锁,而锁是任何对象都具有的,调用任意对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放。而调用任意对象的notify()方法则导致因调用该对象的wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。
其次,wait()和notify()可在任何位置调用,但是这一对方法却必须在 synchronized 方法或块中调用,理由也很简单,只有在 synchronized 方法或块中当前线程才占有锁,才有锁可以释放。同样的道理,调用这一对方法的对象上的锁必须为当前线程所拥有,这样才有锁可以 释放。因此,方法调用必须放置在这样的 synchronized 方法或块中,该方法或块的加锁对象就是调用这些方法的对象。若不满足这一条 件,则程序虽然仍能编译,但在运行时会出现IllegalMonitorStateException 异常。
wait() 和 notify() 方法的上述特性决定了它们经常和synchronized 方法或块一起使用,将它们和操作系统的进程间通信机制作 一个比较就会发现它们的相似性:synchronized方法或块提供了类似于操作系统原语的功能,它们的执行不会受到多线程机制的干扰,而这一对方法则 相当于 block 和wakeup 原语(这一对方法均声明为 synchronized)。它们的结合使得我们可以实现操作系统上一系列精妙的进程间 通信的算法(如信号量算法),并用于解决各种复杂的线程间通信问题。
关于 wait() 和 notify() 方法最后再说明两点:
第一:调用 notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的,我们无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。
第二:除了 notify(),还有一个方法 notifyAll() 也可起到类似作用,唯一的区别在于,调用 notifyAll() 方法将把因调 用该对象的 wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态,
具体唤醒哪一个线程,由jvm来决定。
相关wait和notify使用demo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
/**
* <pre>
* 子线程循环10次,接着主线程循环100次,接着有回到子线程循环10次,
* 接着再回到主线程循环100次,如此执行50次
* </pre>
* @author ketqi
*/
public
class
WaitNotifyDemo {
public
static
void
main(String[] args) {
final
Business business =
new
Business();
new
Thread(
new
Runnable() {
@Override
public
void
run() {
for
(
int
i =
1
; i <=
50
; i++) {
business.sub(i);
}
}
}).start();
for
(
int
i =
1
; i <=
50
; i++) {
business.main(i);
}
}
}
class
Business {
private
boolean
isMainThread =
true
;
public
synchronized
void
sub(
int
i) {
while
(!isMainThread) {
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
for
(
int
j =
1
; j <=
10
; j++) {
System.out.println(
"sub thread sequence of "
+ j +
",loop of "
+ i);
}
isMainThread =
false
;
this
.notify();
}
public
synchronized
void
main(
int
i) {
while
(isMainThread) {
try
{
this
.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
for
(
int
j =
1
; j <=
100
; j++) {
System.out.println(
"main thread sequence of "
+ j +
",loop of "
+ i);
}
isMainThread =
true
;
this
.notify();
}
}
|