[基础]java实现生产者与消费者的三种方式

  时间:2020-08-11 16:29:46  阅读量:1.2k+  评论数:0  作者:fallwind_of_july

学习编程,分析源码很重要,[基础]java实现生产者与消费者的三种方式这篇文章通过代码举例讲述得比较清晰,想了解的可以参考学习一下。

回顾java多线程安全这一part的时候,再学到生产者与消费者的问题。因此写一博客进行记录,同时希望能给在看博客的你提供一些帮助。

这篇文章主要介绍如何通过
  1. synchronized加锁的方式
  2. lock&&Condition的方式
  3. lock&&Condition精准通知与唤醒的方式来实现生产者和消费者
    这三种方式属于层层优化,且都是简单案例,读者可以在此基础上进行扩展。
实现生产者和消费者的主要思路和步骤
  1. 判断等待
  2. 执行业务
  3. 通知唤醒

场景:

  某线程生产一件物品,当该物品被消耗完时才会继续生产;同时另一线程消耗某件物品,当该物品数量大于零时才会继续消耗。通俗来说,就是生产一件物品与消耗一件物品有序交替执行。为了保证物品数量的线程安全,我们需要加锁。

方式一:synchronized

说明:该方式选择在资源类Data的生产和消费方法上加上synchronized从而声明为同步方法。这种方式不推荐。
  Data类为资源类,提供生产和消费的方法。对于生产方法来说,当不满足生产条件时,进入等待状态,在判断满足生产的条件下会执行生产业务,同时唤醒消费者进行消费。对于消费方法来说,当不满足消费条件时,进入等待状态,在判断满足消费的条件下会执行消费业务,同时唤醒生产者进行生产。

public class ProductDemo {

    public static void main(String[] args) {

        Data data = new Data();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.increase();
            }
        },"A").start();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.increase();
            }
        },"B").start();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.decrease();
            }
        },"C").start();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.decrease();
            }
        },"D").start();
    }
}


//判断等待;业务;通知
class Data{
    
    private int num=0;
    
    public synchronized void increase(){
        while (num!=0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        num  ;
        System.out.println(Thread.currentThread().getName() "==>" num);
        this.notifyAll();
    }

    public synchronized void decrease(){
        while (num==0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        num--;
        System.out.println(Thread.currentThread().getName() "==>" num);
        this.notifyAll();
    }
}

方式二:lock&&Condition的普通方式

说明:Condition是java.util.concurrent.locks下的接口,基本的方法就是await()和signal()方法;Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition(),调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用。

public class NewProductDemo {

    public static void main(String[] args) {

        Data2 data = new Data2();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.increase();
            }
        },"A").start();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.increase();
            }
        },"B").start();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.decrease();
            }
        },"C").start();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.decrease();
            }
        },"D").start();
    }
}

//判断等待;业务;通知
class Data2{

    private int num=0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public void increase(){
        lock.lock();
        try {
            while (num!=0) {
                condition.await();
            }
            num  ;
            System.out.println(Thread.currentThread().getName() "==>" num);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void decrease(){
        lock.lock();
        try {
            while (num==0) {
                condition.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName() "==>" num);
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

方式三:lock&&Condition的精准通知与唤醒

说明:由于某些场景下我们要考虑到多个任务的顺序执行,或者需要精准唤醒指定方法,可以考虑使用这种方式。

public class LatestProductDemo {
    public static void main(String[] args) {

        Data3 data = new Data3();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.showA();
            }
        },"A").start();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.showB();
            }
        },"B").start();

        new Thread(()->{
            for(int i=0;i<4;i  ){
                data.showC();
            }
        },"C").start();
    }
}

//判断等待;业务;通知
class Data3{

    private int num=1;
    Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();

    public void showA(){
        lock.lock();

        try {
            while (num!=1) {
                condition1.await();
            }
            num=2;
            System.out.println(Thread.currentThread().getName() "==>" num);
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void showB(){
        lock.lock();

        try {
            while (num!=2) {
                condition2.await();
            }
            num=3;
            System.out.println(Thread.currentThread().getName() "==>" num);
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void showC(){
        lock.lock();
        try {
            while (num!=3) {
                condition3.await();
            }
            num=1;
            System.out.println(Thread.currentThread().getName() "==>" num);
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

关键词:java,多线程,并发编程,基础,实现,生产,生产者,消费,消费者,三种,方式