JUC:4_2并发协作模型:生产者消费者问题:if虚假唤醒,防止虚假唤醒

线程之间的通信,如何交替执行?

线程A、B操作同一个变量numbe=0


/**
 * 线程之间的通信,如何交替执行 ?
 * 线程A、B操作同一个变量numbe=0
 * A++
 * B--
 * <p>
 * 问题:
 * 1.在只有两个线程存在的情况是安全的,再多一个++的和一个--的
 */
public class TestCondition {
    public static void main(String[] args) {
        ServiceImpl service = new ServiceImpl();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    service.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    service.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    service.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    service.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();
    }
}

class ServiceImpl {
    private int number = 0;

    //++
    public synchronized void increment() throws InterruptedException {
//        if (number != 0) {
        while (number != 0) {
            //等待
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "===>" + number);
        //通知其他线程++完毕
        this.notifyAll();
    }

    //--
    public synchronized void decrement() throws InterruptedException {
//        if (number == 0) {
        while (number == 0) {
            //等待
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "===>" + number);
        //通知其他线程--完毕
        this.notifyAll();
    }
}

一个++一个–来操作

在只有两个线程++、–去操作,在只有两个线程存在的情况是安全的

A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0
A===>1
B===>0

两个++和两个–线程同时操作number

两个++和两个–线程同时操作number,都出现了负数

A===>1
B===>0
C===>1
A===>2
C===>3
B===>2
B===>1
B===>0
C===>1
A===>2
C===>3
B===>2
B===>1
B===>0
C===>1
D===>0
A===>1
D===>0
C===>1
B===>0
C===>1
D===>0
A===>1
D===>0
C===>1
B===>0
C===>1
D===>0
A===>1
D===>0
C===>1
B===>0
D===>-1
D===>-2
D===>-3
D===>-4
A===>-3

问题怎么出现的:if和while

怎么出现这种负数:
出现>1,消费者notiyall时,是另外一个正在wait的生产者抢到了锁,执行了++
出现<0,消费者notiyall时,是另外一个正在wait的消费者抢到了锁,执行了–

两个原因

  1. object的wait()方法会释放锁,与sleep抱着锁睡觉不同,释放锁之后,第二个线程就可以获取锁
  2. if只会判断一次,if判断,在if方法体没有执行完的情况下进入锁等待,等再次被唤醒重新时获取锁,不会再去做一次if判断,而是继续执行if里面的内容

if判断为空时,线程被阻塞,这时if判断就已经完成了,线程被唤醒会执行剩余操作

while判断为空时,线程被阻塞,这时while循环没有完成,线程被唤醒后会重新进行while判断

不用while自旋的话,如果多个消费者或者生产者会互相竞争共享资源

object的wait()为什么要用while来判断?

public final void wait() throws InterruptedException

导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。 换句话说,这个方法的行为就好像简单地执行呼叫wait(0) 。
当前的线程必须拥有该对象的显示器。 该线程释放此监视器的所有权,并等待另一个线程通知等待该对象监视器的线程通过调用notify方法或notifyAll方法notifyAll 。 然后线程等待,直到它可以重新获得监视器的所有权并恢复执行。

像在一个参数版本中,中断和虚假唤醒是可能的,并且该方法应该始终在循环中使用:

  synchronized (obj) {
         while (<condition does not hold>)
             obj.wait();
         ... // Perform action appropriate to condition
     } 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值