wait
@Test
public void waitTest() {
new Thread(()->{
System.out.println("wait()前");
try {
wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait()后");
}).start();
}
通过运行上面的测试用例,我们发现会出现如下错误,出现这个错误是因为当前线程wait调用对象没有持有锁,该方法需要调用对象先持有锁才能被调用。而我们在调用的过程中,发现必须得捕获InterruptedException异常,所以wait方法可以响应中断 。
wait正确用法如下:
final Object lock = new Object();
public void startThread1() {
new Thread(()->{
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"wait()前");
synchronized (lock) {
try {
System.out.println(Thread.currentThread().getName() + "-获取锁");
lock.wait();
lock.notify();
System.out.println(Thread.currentThread().getName() + "-唤醒锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"wait()后");
}, "thread-1").start();
}
@Test
public void waitTest() {
startThread1();
try {
synchronized (lock) {
System.out.println("获取锁");
//lock.wait();//这种情况下两个线程都会一直等待
//lock.wait(3000);//等待3s后,唤醒线程,调用notify后唤醒Thread-1
lock.notify();
System.out.println("唤醒等待的锁");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
如上所示,,在waitTest方法中同步快获取锁后,调用了wait后,Thread-1中同步块可以获取到锁,在获取锁后调用wait方法后waitTest中wait方法并没有立即结束等待,而是在等待足时后才执行后面的语句,如果两个线程中的wait方法都不带参数的话,两个线程都会一直等待。因此,wait方法可以释放锁,但是并不能唤醒其他wait状态的线程,wait不带参数的等待状态必须要notify或者notifyAll才能唤醒
sleep
sleep方法是Thread的方法,在调用时也需要处理InterruptedException ,所以sleep也是可以响应中断的,在使用sleep方法时必须要携带一个或者两个时间参数,第二个参数为时间单位。
总结
相同点:都会使当前线程暂停;当wait使用带参数方法时可以和sleep方法一样,使线程处于监控状态,到达监控时间时候会重新唤醒当前线程;同时在等待的时候都会让出cpu时间;wait和sleep方法都可以响应中断
不同点:wait方法数据Object对象,需要在获取锁的情况下才能使用,同时wait方法会释放锁,当wait使用不带参数方法时,必须由notify或者notifyAll方法唤醒;而sleep方式是Thread的静态方法,使用时不比关注锁状态,也不能释放锁