JUC-线程间通讯(sychronized/lock)

线程间通讯 :

多个线程在处理同一个资源的时候,当线程处理的任务不同。默认的情况下cpu是在随机切换线程,那你邮箱多个线程可以有规律的执行,那么多线程之间需要一些协调通信;
需要线程通信来帮助解决线程之间对同一个变量的使用或操作,就是多个线程在操作同一份数据时,避免对同一共享变量的争夺。也就是我们需要通过一定的手段使各个线程能有效地利用资源,这种手段即——等待唤醒机制

比如我们实现实现一个线程对该变量加1,一个线程对该变量减1,* 交替,来10轮。

这个就是典型的生产者+消费者+通知等待唤醒机制

使用synchronized方式实现:

  • 1:判断
  • 2:干活
  • 3:通知

资源类ShartDataOne:

class ShartDataOne {
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition cd = lock.newCondition();


    public synchronized void increment() throws InterruptedException
    {
        //1判断
        if(number !=0 ) {
            this.wait();
        }
        //2干活
        ++number;
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //3通知
        this.notifyAll();
    }
    public synchronized void decrement() throws InterruptedException
    {
        // 1判断
        if (number == 0) {
            this.wait();
        }
        // 2干活
        --number;
        System.out.println(Thread.currentThread().getName() + "\t" + number);
        // 3通知
        this.notifyAll();
    }
}

#当只有两个线程的时候,即A1线程负责+操作,B1负责-操作
在这里插入图片描述

此时运行结果都是顺序执行:
在这里插入图片描述

但是当我们增加到4个线程的时候,A1,A2负责+,B1,B2负责-

在这里插入图片描述
此时的运行结果却不是我们的预期:
在这里插入图片描述

上面的结果就出现了虚假唤醒的结果:

为什么换成四个线程就出现了虚假唤醒

问题就是出现在我们的判断上使用了if,为什么使用了if会出现这种问题呢?

  • 1: 首先我们在方法上加入了synchronized代表这是一个同步方法,如果这个对象有多个synchronized方法的话,当一个线程进入了其中一个,其他线程就只能等待这个线程释放锁,才能访问其他的synchronized方法;因为在方法上加入关键字synchronized,锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法
    换成两个对象后,不是同一把锁了,情况立刻变化。
  • 2: 我们在主方法中都是调用同一个对象实例,所以上面的讲的也就是为什么一开始两个线程能成功的原因,但是换成四个就不能成功?
  • 3:因为if判断只能判断一次,例如:默认都是0,如果B1先进来,if判断了(number==0)=true,那么B1就会this.wait(),交出锁。默认的情况下cpu是在随机切换线程;接下来如果B1再次抢到锁,进入后并不是执行判断if,而是从wait()后继续执行,也就是–,所以此时的number就是-1,。。。。。。

那有上面的办法解决呢

就是将判断if换成while,比如上面举的例子,如果使用了while,B1在次抢到锁,还得进行while判断,继续wait();

如果使用JUC中的Lock来实现呢?

使用Lock实现

类比sychronized方式:
在这里插入图片描述
使用Lock实现:对标wait与notify的是Condition: await和signal

在Lock接口上可以看到:
在这里插入图片描述
Lock的实现类都可以返回个Condition对象

Condition

在这里插入图片描述

  • Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.
  • 将((wait, notify and notifyAll)分解为对象,也就是Condition
    在这里插入图片描述

资源类:

class ShartDataOne {
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition cd = lock.newCondition();


    /**
     * 同步方法 使number++
     *
     * @Author:LRC
     * @Date:11:17 上午 2020/7/3
     */
    public void increment() throws InterruptedException {

        lock.lock();
        try {
            while (number != 0) {
                cd.await();
            }
            ++number;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            //通知
            cd.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    /**
     * 同步方法 使number--
     *
     * @Author:LRC
     * @Date:11:18 上午 2020/7/3
     */
    public void decrement() throws InterruptedException {
        lock.lock();
        try {
            //判断
            while (number != 1) {
                cd.await();
            }
            --number;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            //通知
            cd.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

同样是4个线程没出错

实现线程通讯注意在判断上不要使用if
将synchronized方式慢慢转变成使用lock
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值