java.lang.Object类中提供了两个用于线程通信的方法:wait()和notify()。如果线程对一个同步对象this发出一个wait()调用,该线程会暂停执行,直到另一个线程对同一个同步对象this也发出一个notify()调用,释放加在对象上的“锁”。
为了让线程对一个对象调用wait()或notify(),线程必须锁定那个特定的对象。
也就是说,只能在它们被调用的实例的同步块内使用wait()和notify()。
对于这个实例来说,需要一个以synchronized(cab)开始的块来允许执行cab.wait()和cab.notify()调用。
wait():告诉当前线程放弃监视器并进入睡眠状态,直到其他线程进入同一监视器并调用notify()为止。使线程休眠一段时间,若设置参数,时间到时,线程就自动进入可执行状态。若没有,则需要notify()方法去调用。
notify():唤醒同一对象监视器中调用wait的第一个线程。
notifyAll():唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。
wait(),notify(),notifyAll()这三个方法只能在synchronized方法中调用。
下面看个例子
public class TestWait {
public static void main(String[] args) {
Thread1 t1=new Thread1();
Thread2 t2=new Thread2();
t1.setName("线程1");
t2.setName("线程2");
Object o1=new Object();
Object o2=new Object();
t1.o1=o1;
t2.o1=o1;
t1.start();
t2.start();
}
static class Thread1 extends Thread{
Object o1;
@Override
public void run() {
synchronized(o1){
for(int i=0;i<50;i++){
if(i==10){
try {
o1.wait();//当前线程等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(getName()+" "+i);
}
}
}
}
static class Thread2 extends Thread{
Object o1;
@Override
public void run() {
synchronized (o1) {
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<50;i++){
System.out.println(getName()+" "+i);
}
o1.notify();//唤醒在o1上等待的线程对象
}
}
}
}
下面实现一个简单的阻塞队列:
public class BlockingQueueDemo {
public static void main(String[] args) throws InterruptedException {
BlockingQueueDemo blockingQueue=new BlockingQueueDemo();
Thread t1=new Thread(()->{try {
while (true) {
System.out.println(blockingQueue.remove());
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}});
t1.start();
for (int i = 0; i < 10; i++) {
blockingQueue.add(1);
Thread.sleep(1000);
}
}
private List queue = new LinkedList();
public synchronized void add(Object item)throws InterruptedException {
queue.add(item);
notifyAll();
}
public synchronized Object remove()throws InterruptedException {
while (queue.size() == 0) {
wait();
}
return queue.remove(0);
}
}