为什么 wait 或者 Condition 的 await 要放在同步块中

我们一般的写法就是 对象的 wait 或者 Condition 的 await 方法都放在 同步块中,为什么要这样呢?

可能有人说不这样会报 IllegalMonitorStatesException,这个应该是结果而不是原因,面试中这样说肯定是不成的。

要说明这个问题,我这里用生产、消费者模型来做说明,用的是 Conditionawaitsignal 方法。

下面直接来看代码:


class ConAndProService{
    private final static Stack<Integer> list = new Stack<>(); //list里面只存放一个数据
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void producer(){
        try {
            lock.lock();
            while (list.size() == 1){ //注1
                condition.await();
            }
            int val = new Random().nextInt(10)+1;
            System.out.println("ThreadName : "+Thread.currentThread().getName()+" ...........producer val ........ = "+val);
            list.add(val);
            condition.signal(); //注2
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void consumer(){
        try {
            lock.lock();
            while (list.size() == 0){//注3
                condition.await();//注4
            }
            int val = list.pop();
            System.out.println("ThreadName : "+Thread.currentThread().getName()+"*************** consumer val *************** = "+val);
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

现在我们假设 没有加 同步块 ,那么就会发生下面的结果:

1. 假设消费者先开始执行,执行完注释3 , 但是并没有执行注释4就发生上下文切换,执行到注释1 ;
2. 因为 list 里面没值 所以往里面 add 然后 执行注释 2,发出 signal,由于此时 消费者 还没有执行 wait 所以signal 无效;
3. 再次发生上下文切换,由于注3 之前执行过了,直接 await 了,消费者线程阻塞了;
4. 然后再次执行注释1,由于 list中的数据没有被消费掉,所以执行 await 导致 生产者线程也阻塞了。

如果有同步块就不会发生上述情况了, 因为同步块同一时间只能有一个线程可以执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值