JUC基础-C3-线程间通信

1 线程间通信

1.1 wait()和notify()完成通信

完成一个例子,线程A和线程B对变量value进行操作,value初始值为0,线程A当value的值为0时给其加1
线程B当value的值为1时给其减1,通过wait()notify()来完成线程A和线程B的通信
public class Value {

    private int number;

    public Value() {}

    public synchronized void incr() throws InterruptedException {
        if(number != 0) {
            this.wait();
        }
      	  number++;
          System.out.println(Thread.currentThread().getName() + ": " + number);
          this.notifyAll();
    }

    public synchronized void decr() throws InterruptedException {
        if (number != 1) {
            this.wait();
        }
          number--;
          System.out.println(Thread.currentThread().getName() + ": " + number);
          this.notifyAll();
    }

}

在这里插入图片描述

1.2 wait()的虚假唤醒问题

将上述的程序增加两个线程,分别完成自增和自减,理想中由于if的存在,结果仍然是1和0交替出现,但是执行后可以看到:
在这里插入图片描述
之所以产生上述的问题,是由于wait()方法的虚假唤醒问题,考虑如下情况:

考虑A拿到锁开始执行 此时判断通过 number++ number=1 notifyAll()
C拿到锁开始执行 此时判断未通过 C释放锁等待
A拿到锁开始执行 此时判断未通过 A释放锁等待
C拿到锁开始执行 从上次wait()之后的代码继续执行 number++ number=2 notifyAll()

为了解决wait()的虚假唤醒问题,只需线程每次醒来后再进行一次判断即可

	public synchronized void incr() throws InterruptedException {
        while (number != 0) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + " :" + number);
        this.notifyAll();
    }

1.3 Lock完成通信

使用Lock接口的实现类ReentrantLock作为锁
并通过condition的await()/signal()完成线程间的通信

	public class Value {

    private final ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    private int number;

    public void incr() {
        lock.lock();
        try {
            while (number != 0) {
                condition.await();
            }

            number++;
            System.out.println(Thread.currentThread().getName() + " :" + number);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void decr() {
        lock.lock();
        try {
            while (number != 1) {
                condition.await();
            }

            number--;
            System.out.println(Thread.currentThread().getName() + " :" + number);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

1.4 线程间定制化通信

完成示例,A线程先打印5次,B线程再打印10次,C线程再打印15次 依次循环此过程10轮
通过多个Condition和flag来完成确定的唤醒
public class Test {

    // 通信判断用标志位
    private int flag = 1;

    private final ReentrantLock lock = new ReentrantLock();
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    private Condition c3 = lock.newCondition();

    public void taskA(int loop) {
        lock.lock();

        try {
            while (flag != 1) {
                c1.await();
            }

            for(int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + " : " + i + " loop:" + loop);
            }
            flag = 2;
            c2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

...

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值