wait是object中的方法,使用wait方法时要在同步代码块中,并且经常和notify和notifyAll一起使用,用于线程之间的通信。线程调用wait时,当前线程就会休眠并且释放锁,等待其他线程调用notify或者notifyAll来唤醒。
sleep是Theard类中的静态方法,可以不在同步块中使用,用于线程休眠一段时间后自己醒来。线程调用sleep后不会释放锁,如果此时有其他的线程要获取该锁,就会一直等待。
一个完整的demo
为了深入学习wait()和notify(),先用完整的demo程序来模拟场景吧,以下是源码:
public class NotifyDemo {
private static void sleep(long sleepVal){
try{
Thread.sleep(sleepVal);
}catch(Exception e){
e.printStackTrace();
}
}
private static void log(String desc){
System.out.println(Thread.currentThread().getName() + " : " + desc);
}
Object lock = new Object();
public void startThreadA(){
new Thread(() -> {
synchronized (lock){
log("get lock");
startThreadB();
log("start wait");
try {
lock.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
log("get lock after wait");
log("release lock");
}
}, "thread-A").start();
}
public void startThreadB(){
new Thread(()->{
synchronized (lock){
log("get lock");
startThreadC();
sleep(100);
log("start notify");
lock.notify();
log("release lock");
}
},"thread-B").start();
}
public void startThreadC(){
new Thread(() -> {
synchronized (lock){
log("get lock");
log("release lock");
}
}, "thread-C").start();
}
public static void main(String[] args){
new NotifyDemo().startThreadA();
}
}
以上就是本次实战用到的demo,代码功能简述如下:
- 启动线程A,取得锁之后先启动线程B再执行wait()方法,释放锁并等待;
- 线程B启动之后会等待锁,A线程执行wait()之后,线程B取得锁,然后启动线程C,再执行notify唤醒线程A,最后退出synchronize代码块,释放锁;
- 线程C启动之后就一直在等待锁,这时候线程B还没有退出synchronize代码块,锁还在线程B手里;
- 线程A在线程B执行notify()之后就一直在等待锁,这时候线程B还没有退出synchronize代码块,锁还在线程B手里;
- 线程B退出synchronize代码块,释放锁之后,线程A和线程C竞争锁;
把上面的代码在Openjdk8下面执行,反复执行多次,都得到以下结果:
thread-A : get lock
thread-A : start wait
thread-B : get lock
thread-C : c thread is start
thread-B : start notify
thread-B : release lock
thread-A : after wait, acquire lock again
thread-A : release lock
thread-C : get lock
thread-C : release lock