JUC(2)生产者消费者问题&&锁问题

使用synchronized关键字实现生产者消费者问题

步骤:

  1. 判断是否需要等待
  2. 业务
  3. 通知
public class Demo {
    public static void main(String[] args) {
        Data data = new Data();
        // 线程A,进行加1
        new Thread(()->{
            try {
                // 10 次操作
                for (int i = 0; i < 10; i++) {
                    data.increment();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"线程A").start();

        // 线程B,进行减1
        new Thread(()->{
            try {

                for (int i = 0; i < 10; i++) {
                    data.decrement();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"线程B").start();

        // 线程A,进行加1
        new Thread(()->{
            try {
                // 10 次操作
                for (int i = 0; i < 10; i++) {
                    data.increment();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"线程C").start();

        // 线程B,进行减1
        new Thread(()->{
            try {

                for (int i = 0; i < 10; i++) {
                    data.decrement();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"线程D").start();

    }
}

业务代码:

/**
 * 待操作的Data资源类,需要解耦
 */

class Data{
    private int num = 0;

    public synchronized void increment() throws InterruptedException {
        while(num != 0){
            // 1.等待:有东西不需要生产
            this.wait();
        }
        System.out.println(Thread.currentThread().getName() + "=> " + num);
        num ++;//2.业务:生产一个
        this.notifyAll(); //3.通知:唤醒其他线程
    }

    public synchronized void decrement() throws InterruptedException {
        while(num == 0){
            // 1.等待:没东西不能消费
            this.wait();
        }
        System.out.println(Thread.currentThread().getName() + "=> " + num);
        num --;2.业务:消费一个

        this.notifyAll();3.通知:唤醒其他线程
    }
}

使用if判断会造成虚假唤醒问题
这里不能将while改为if判断
因为if只判断一次,等待队列的多个消费者被生产者唤醒后重新进入同步队列,这时候抢到锁,会从if下面的语句开始执行,相当于没了判断

使用Lock锁实现生产者消费者问题

  • Condition接口取代了Object监视器方法(wait、notify、notifyAll)使用自己的方法完成线程间通信
  • 使用lock对象的newCondition()方法可以获得condition对象,该对象有一个await()方法(等待)和singal()方法(通知唤醒其他线程)
  • 同时Condition支持精准的通知、唤醒线程(使线程按照顺序执行)
class Data{
    private int num = 0;

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public  void increment()  {

        // 加锁
        lock.lock();

        try {
            while(num != 0){
                // 等待
                condition.await();
            }
            System.out.println(Thread.currentThread().getName() + "=> " + num);
            num ++;
            
            // 唤醒
            condition();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }

    public  void decrement()  {
        // 加锁
        lock.lock();

        try {
            while(num == 0){
                // 等待
                condition.await();
            }
            System.out.println(Thread.currentThread().getName() + "=> " + num);
            num --;
            
            // 唤醒
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }
}

总结:

在这里插入图片描述

wait()和sleep()的区别

  • 来自不同的类,wait来自Object,sleep来自Thread
  • 锁是否是否释放不同,wait会释放锁,sleep不会释放锁
  • 使用范围不同,wait必须放在同步代码块中(与显示锁Lock对应)
  • 是否需要异常捕获,wait不需要异常捕获,sleep需要异常捕获

锁问题

同一资源类下,使用synchronized修饰的普通方法 ,是当前资源类的对象锁,也就是锁是调用者方法的对象。谁先拿到谁执行。(不同对象锁是不会互相干扰的);
如果是static静态方法修饰的,是锁住了Class类

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值