初阶并发编程之——运用wait()与notify()实现线程之间的协作

wait()与notifyAll()

  wait()方法和notifyAll()方法都属于Object类的final方法,即子类不可重写该方法。wait()正如字面等待的意思,导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。wait()与sleep()不同的是,wait()先将锁释放再去挂起线程,所以wait()必须再同步块或方法中调用。方法notifyAll()唤醒正在等待对象监视器的所有线程。notify仅唤醒一个线程并允许它去获得锁,notifyAll是唤醒所有等待这个对象的线程并允许它们去获得对象锁,只有是在synchronied块/方法中才能调用该方法。

  下面有个自己写的实例,关于老师提问和学生回答的场景:老师问一个问题后学生才能回答问题,学生回答完问题老师才能问下一个问题。代码如下:

class AnswerAndQuestion{
    private boolean IsOrNo = false;           //老师是否问问题了,true表示问了,false表示没有

    public synchronized void question() throws InterruptedException{

        if(IsOrNo){                  //如果已经问了那就挂起
            wait();
        }else{
            if(Teacher.i == 1){
                System.out.println("老师:2乘2等于多少?");
            }else if( Teacher.i==2){
                System.out.println("老师:3乘3等于多少?");
            }else if(Teacher.i==3){
                System.out.println("老师:4乘4等于多少?");
            }else{
                wait();           //没问题时先挂起
            }
            IsOrNo = true;

            //问完一个问题等学生答完再问
            notifyAll();             //将学生的线程唤醒
        }
    }
    public synchronized void answer() throws InterruptedException{
        if(!IsOrNo){               //如果老师没有问了问题了那就挂起
            wait(); 
        }else{
            TimeUnit.SECONDS.sleep(2);     //模拟学生思考2秒
            if(Teacher.i == 1){
                System.out.println("学生:4");
            }else if( Teacher.i==2){
                System.out.println("学生:9");
            }else if(Teacher.i==3){
                System.out.println("学生:16");
            }
            if(Teacher.i>0&&Teacher.i<3){
                System.out.println("老师:下一个问题!");
            }
            Teacher.i++;
            IsOrNo = false;      //答完问题将问题改为没有问问题
            notifyAll();         //将老师的线程唤醒
        }
    }
}
class Teacher implements Runnable{
    private AnswerAndQuestion aq;
    public static int i=1;
    public Teacher(AnswerAndQuestion aq){
        this.aq = aq;
    }
    @Override
    public void run() {
        try {
            while(true){
                aq.question();      //问完问题在学生回答之前将自己挂起
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}
class Student implements Runnable{
    private AnswerAndQuestion aq;
    public static int i=1;
    public Student(AnswerAndQuestion aq){
        this.aq = aq;
    }
    @Override
    public void run() {
        try {
            while(true){
                aq.answer();
                i++;
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}
public class AnswerQuestion {
  public static void main(String[] args) {
      ExecutorService exec = Executors.newCachedThreadPool();
      AnswerAndQuestion aq = new AnswerAndQuestion();
      exec.execute(new Teacher(aq));
      exec.execute(new Student(aq));
  }
}

输出结果如下:

老师:2乘2等于多少?
学生:4
老师:下一个问题!
老师:3乘3等于多少?
学生:9
老师:下一个问题!
老师:4乘4等于多少?
学生:16


  老师和学生通过共同对变量IsOrNo来选择是将自己挂起还是执行问和答并将对方唤醒。当然最后三个问题答完老师和学生都挂起了,没有中断是因为无法预测三个问题问答的时间。从代码注释中可以看出:先是IsOrNo为false,表示老师没有问问题,然后就可以问一第一个问题了(执行同步方法quertion())。问完将IsOrNo改为true并唤醒老师,Teacher中run方法第二次循环时线程被挂起,等待唤醒再问第二个;与之同时的是学生线程也在异步的进行,因为IsOrNo为false所以挂起,等待唤醒,而老师那边问完问题刚好又唤醒了,所以回答了老师的问题,并将老师唤醒,问第二个问题。故此逻辑,实现了老师与学生两个线程的简单协同。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值