区别1: sleep() 可以放在任意method的内部,每当有一个thread走到sleep()的位置,这个线程会马上变为阻塞状态。比如同时有两个线程都同时遇到了sleep(),那两个thread同时都会马上变成阻塞状态,直到sleep时间过去之后才会变成wait状态,等待操作系统分配CPU时间戳。所以Sleep()操作是线程级别的,不需要与其它对象协同,可以直接放到Thread类中。

wait()也是让一个线程变成阻塞状态,但是这个阻塞必须要一个额外的锁来协同,阻塞的线程会放到这个锁的waiting queue之中。然后释放这个锁。如果当前线程没有拥有锁,那么这个线程调用wait()时会抛出异常。

所以调用某个线程调用wait时,必须放在synchronized 内部,这样才能保证这个线程获得了一把锁。

在Java中任何对象(Object)都可以成为一个Monitor, 这个Monitor由锁(lock), 等待队列(waiting queue), 入口队列(entry queue)组成。锁(lock)就是可以分配的资源,只有一个线程能拿到这个锁,这个线程就是Owner, 其它没有拿到锁的线程只能先进入入口队列(entry queue)中等待锁的释放。如下图所示:

img

wait() 就是将锁的owner放入wait queue. notify()就是把wait queue中阻塞的线程放到entry queue中。

wait() 和 notify() 要放在同一把锁的synchronization块中,因为wait() 和 notify() 不能同时被两个线程调用,wait()和notify()之间是有一定顺序的,一般是先wait()之后再notify(). 所以需要synchronized同步块来限制一次只有一个线程能适应wait()或者notify();

区别2:如果sleep在synchronized块之内,那么sleep的线程是不会释放锁资源的。其它线程仍然无法进入synchronized块之中。这个线程必须跑完synchronized块才会释放锁资源。
wait() 则会马上释放锁资源,所以wait()之后其它的线程就可以马上synchronized块之中了。

以下是一个example:

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
61
public class MultiThread {

private static class Thread1 implements Runnable{
@Override
public void run() {
//由于 Thread1和下面Thread2内部run方法要用同一对象作为监视器,如果用this则Thread1和Threa2的this不是同一对象
//所以用MultiThread.class这个字节码对象,当前虚拟机里引用这个变量时指向的都是同一个对象
synchronized(MultiThread.class){
System.out.println("enter thread1 ...");
System.out.println("thread1 is waiting");

try{
//释放锁有两种方式:(1)程序自然离开监视器的范围,即离开synchronized关键字管辖的代码范围
//(2)在synchronized关键字管辖的代码内部调用监视器对象的wait()方法。这里使用wait方法
MultiThread.class.wait();
}catch(InterruptedException e){
e.printStackTrace();
}

System.out.println("thread1 is going on ...");
System.out.println("thread1 is being over!");
}
}

}

private static class Thread2 implements Runnable{
@Override
public void run() {
//notify方法并不释放锁,即使thread2调用了下面的sleep方法休息10ms,但thread1仍然不会执行
//因为thread2没有释放锁,所以Thread1得不到锁而无法执行
synchronized(MultiThread.class){
System.out.println("enter thread2 ...");
System.out.println("thread2 notify other thread can release wait status ...");
MultiThread.class.notify();
System.out.println("thread2 is sleeping ten millisecond ...");

try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}

System.out.println("thread2 is going on ...");
System.out.println("thread2 is being over!");
}
}
}

public static void main(String[] args) {
new Thread(new Thread1()).start();
try{
Thread.sleep(10);
}catch(InterruptedException e){
e.printStackTrace();
}

new Thread(new Thread2()).start();
}

}

以上代码的输出结果为:

1
2
3
4
5
6
7
8
9
enter thread1 ...
thread1 is waiting
enter thread2 ...
thread2 notify other thread can release wait status ... // 这里虽然notify了thread1,但thread2没有释放锁资源, thread1唤醒之后仍然无法往前走动
thread2 is sleeping ten millisecond ...
thread2 is going on ...
thread2 is being over! //当thread2走出synchronized块后,释放锁资源,thread1这时候可以往后运行了。
thread1 is going on ...
thread1 is being over!

https://blog.csdn.net/u012050154/article/details/50903326

https://zhuanlan.zhihu.com/p/76625784