一、wait与notify
1.wait()方法
语义:使得当前线程立刻停止运行,处于等待状态(WAIT),并将当前线程置入锁对象的等待队列中,直到被通知(notify)或被中断为止。
使用条件:wait方法只能在同步方法或同步代码块中使用,而且必须是内建锁。wait方法调用后立刻释放对象锁
wait方法的重载
1)public final void wait() throws InterruptedException——死等,直到被唤醒或中断
2)public final native void wait(long timeout) throws InterruptedException——超时等待:若在规定时间内未被唤醒,则线程退出,单位:毫秒
3)public final void wait(long timeout, int nanos) throws InterruptedException——在2的基础上增加了纳秒控制
2.notify()方法
语义:唤醒处于等待状态的线程
使用条件:notify()也必须在同步方法或同步代码块中调用,用来唤醒等待该对象的其他线程。如果有多个线程在等待,随机挑选一个线程唤醒(唤醒哪个线程由JDK版本决定)。notify方法调用后,当前线程不会立刻释放对象锁,要等到当前线程执行完毕后再释放锁。
3.notifyAll()方法
唤醒所有处于等待状态的线程
class myThread implements Runnable{
private boolean flag ;
private Object object ;
myThread(boolean flag, Object o){
this.flag = flag;
this.object = o;
}
private void waitThread(){
synchronized (object) {
System.out.println(Thread.currentThread().getName() + "wait begin...");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "wait end...");
}
}
private void notifyThread(){
synchronized (object) {
System.out.println(Thread.currentThread().getName() + "notify begin...");
object.notify();
System.out.println(Thread.currentThread().getName() + "notify end...");
}
}
@Override
public void run() {
if(flag){
waitThread();
}else {
notifyThread();
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
myThread mt2 = new myThread(false,object);
Thread thread1 = new Thread(mt2,"线程B ");
for (int i = 0;i<10;i++) {
myThread mt = new myThread(true,object);
Thread thread = new Thread(mt,"线程A "+i);
thread.start();
}
Thread.sleep(1000);
thread1.start();
}
}
输出
这段代码中,开启了10个线程去执行waitThread()方法,可以发现10个线程都处于等待状态,1秒后开启一个线程去执行notifyThread(),可见notify唤醒了0号线程,0号线程等待结束。当我们把notify()改成notifyAll()后,会唤醒所以等待的线程,效果如下,而且可以发现notify没有立刻释放对象锁,唤醒后的顺序与等待的顺序正好相反,所以他是等到当前线程执行完毕后再释放锁。
二、线程出现阻塞的情况(线程由运行到阻塞)
1.线程调用sleep()方法。立刻交出CPU,但不释放锁
2.线程调用阻塞式IO(BIO)方法
3.线程获取锁失败进入阻塞状态
4.线程调用wait()方法
5.线程调用suspend()方法,将线程挂起,此方法容易导致死锁
每个锁对象都有2个队列。一个称为同步队列,存储获取锁失败的线程。另一个称为等待队列,存储调用wait()等待的线程。将线程唤醒实际上是将处于等待队列的线程移到同步队列中竞争锁。