java多线程中的生产者消费者实现

一.wait()和notifyAll()/notify()协作

首先定义资源类:

public class Resource {

    private String name;
    private int age;
    private boolean flag;   //false代表资源为空 true代表资源待消耗

    /**
     * 生产数据
     * @param name
     */
    public synchronized void produce(String name){
        System.out.println(Thread.currentThread().getName() + "竞争到了生产锁,flag="+ flag);
        if (flag == true){    //说明现在资源是待消耗的			//TODO 注意这里用if是错误的  应该把if换成while  具体原因请分析输出结果Tom3
            try {
                wait();         //所以生产进入等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.name = name;
        this.age = age;
        age++;
        System.out.println(Thread.currentThread().getName() + "生产了:"+ name + ","+ age);
        flag = true;            //生产了之后资源就是待消耗的
        notifyAll();            //唤醒等待的消费线程
    }
    /**
     * 取数据,消费数据
     * @return
     */
    public synchronized void consume(){
        System.out.println(Thread.currentThread().getName() + "竞争到了消费锁,flag="+ flag);
        if (flag == false){      //说明资源是空的			//TODO 注意这里用if是错误的  应该把if换成while  具体原因请分析输出结果Tom3
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + "消费了:"+this.name+","+this.age);
        flag = false;           //消费之后资源就是空的
        notifyAll();            //唤醒其他的生产线程
    }

}

生产者:

public class Producer implements Runnable{

    //共享资源对象
    Resource p = null;

    public Producer(Resource p){
        this.p = p;
    }

    public void run() {
        //生产对象
        for(int i = 0 ; i < 10 ; i++){
            p.produce("Tom");
        }
    }
}

消费者:

public class Consumer implements Runnable{

    //共享资源对象
    Resource p = null;

    public Consumer(Resource p) {
        this.p = p;
    }

    public void run() {
        for(int i = 0 ; i < 10; i++){
            //消费对象
            p.consume();
        }
    }
}

测试类:

public class Test {

	public static void main(String[] args) {

        Resource person = new Resource();
        Producer producer = new Producer(person);
        Consumer consumer = new Consumer(person);

        Thread threadProducer = new Thread(producer); // 创建1个生产者线程
        threadProducer.setName("生产线程1");
        Thread threadProducer1 = new Thread(producer); // 创建1个生产者线程
        threadProducer1.setName("生产线程2");
        Thread threadComsumer = new Thread(consumer); // 创建1个消费者线程
        threadComsumer.setName("消费线程1");
        Thread threadComsumer1 = new Thread(consumer); // 创建1个消费者线程
        threadComsumer1.setName("消费线程2");
        threadProducer.start(); // 分别开启线程
        threadComsumer.start();
        threadProducer1.start();
        threadComsumer1.start();

    }

}

输出结果(每次结果不一样,因为线程竞争是随机的,我选择了错误比较明显的,错误在生产Tom3之后没有消费,就是因为if判断的原因,把代码里面的if判断换成while就好了):

生产线程1竞争到了生产锁,flag=false
生产线程1生产了:Tom,1
生产线程1竞争到了生产锁,flag=true
消费线程1竞争到了消费锁,flag=true
消费线程1消费了:Tom,1
消费线程1竞争到了消费锁,flag=false
生产线程1生产了:Tom,2
生产线程1竞争到了生产锁,flag=true
生产线程2竞争到了生产锁,flag=true
消费线程1消费了:Tom,2
消费线程1竞争到了消费锁,flag=false
消费线程2竞争到了消费锁,flag=false
生产线程2生产了:Tom,3
生产线程2竞争到了生产锁,flag=true
生产线程1生产了:Tom,4
生产线程1竞争到了生产锁,flag=true
生产线程2生产了:Tom,5
生产线程2竞争到了生产锁,flag=true
消费线程2消费了:Tom,5
消费线程2竞争到了消费锁,flag=false
消费线程1消费了:Tom,5
消费线程1竞争到了消费锁,flag=false
消费线程2消费了:Tom,5
消费线程2竞争到了消费锁,flag=false
生产线程2生产了:Tom,6
生产线程2竞争到了生产锁,flag=true
生产线程1生产了:Tom,7
生产线程1竞争到了生产锁,flag=true
生产线程2生产了:Tom,8
生产线程2竞争到了生产锁,flag=true
消费线程2消费了:Tom,8
消费线程2竞争到了消费锁,flag=false
消费线程1消费了:Tom,8
消费线程1竞争到了消费锁,flag=false
消费线程2消费了:Tom,8
消费线程2竞争到了消费锁,flag=false
生产线程2生产了:Tom,9
生产线程2竞争到了生产锁,flag=true
生产线程1生产了:Tom,10
生产线程1竞争到了生产锁,flag=true
生产线程2生产了:Tom,11
生产线程2竞争到了生产锁,flag=true
消费线程2消费了:Tom,11
消费线程2竞争到了消费锁,flag=false
消费线程1消费了:Tom,11
消费线程1竞争到了消费锁,flag=false
消费线程2消费了:Tom,11
消费线程2竞争到了消费锁,flag=false
生产线程2生产了:Tom,12
生产线程2竞争到了生产锁,flag=true
生产线程1生产了:Tom,13
生产线程1竞争到了生产锁,flag=true
生产线程2生产了:Tom,14
生产线程2竞争到了生产锁,flag=true
消费线程2消费了:Tom,14
消费线程2竞争到了消费锁,flag=false
消费线程1消费了:Tom,14
消费线程1竞争到了消费锁,flag=false
消费线程2消费了:Tom,14
消费线程2竞争到了消费锁,flag=false
生产线程2生产了:Tom,15
生产线程2竞争到了生产锁,flag=true
生产线程1生产了:Tom,16
生产线程1竞争到了生产锁,flag=true
生产线程2生产了:Tom,17
消费线程2消费了:Tom,17
消费线程2竞争到了消费锁,flag=false
消费线程1消费了:Tom,17
消费线程1竞争到了消费锁,flag=false
消费线程2消费了:Tom,17
生产线程1生产了:Tom,18
生产线程1竞争到了生产锁,flag=true
消费线程1消费了:Tom,18
消费线程1竞争到了消费锁,flag=false
生产线程1生产了:Tom,19
生产线程1竞争到了生产锁,flag=true
消费线程1消费了:Tom,19
消费线程1竞争到了消费锁,flag=false
生产线程1生产了:Tom,20
消费线程1消费了:Tom,20

总结一下:

  1. wait()方法是Object的方法,会使调用当前对象wait()的线程进入当前对象的等待池,如果在等待的过程中被唤醒(notifyAll()/notify()),线程就会进入当前对象的竞争池,如果竞争到了当前对象的锁,那么线程会从wait()方法之后开始继续往下执行,注意是wait()方法之后,而不是重新进入方法,这也是上面if判断错误的原因
  2. notifyAll()/notify()用于唤醒当前对象等待池中的线程,让等待池中的线程进入竞争池,竞争当前对象的锁,notifyAll()会唤醒在当前对象等待池中的所有等待线程进入竞争,notify()会唤醒当前对象等待池中的随机一个线程进入竞争,notify()唤醒的时候等待池中的线程优先级越高越有可能优先被唤醒。notifyAll()和notify()唤醒等待的线程,但是当前执行notifyAll()或notify()的线程不会立刻让出当前线程的锁,而是在notifyAll()/notify()所在的同步方法执行完之后,才会放开当前对象的锁,然后被唤醒的线程才会去竞争

二. BlockingQueue方式

生产者:

import java.util.concurrent.BlockingQueue;

public class ProducerQueue implements Runnable {

    private final BlockingQueue proQueue;

    public ProducerQueue(BlockingQueue proQueue) {
        this .proQueue =proQueue;
    }

    @Override
    public void run() {

        for (int i=0;i<10;i++) {
            try {
                System. out .println("生产了【" + i + "】号产品");
                proQueue.put(i);
                System. out .println("【" + i + "】号产品放入了缓冲容器");
            } catch (InterruptedException  e) {
                e.printStackTrace();
            }

        }

    }
}

消费者:

import java.util.concurrent.BlockingQueue;

public class ConsumerQueue implements Runnable {

    private final BlockingQueue conQueue;

    public ConsumerQueue(BlockingQueue conQueue) {
        this .conQueue =conQueue;
    }

    @Override
    public void run() {
        for (int i=0;i<10;i++) {
            try {
                System.out.println("消费了【" + conQueue.take() + "】号产品");
                Thread.sleep(2000);  //sleep模拟真实环境
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class PublicBoxQueue {

    public static void main(String []args)
    {
        BlockingQueue publicBoxQueue= new LinkedBlockingQueue(5);   //定义了一个大小为5的盒子

        Thread pro= new Thread(new ProducerQueue(publicBoxQueue));
        Thread con= new Thread(new ConsumerQueue(publicBoxQueue));
 
        pro.start();
        con.start();
    }

}

输出结果(结果可能不同,因为线程竞争随机的):

生产了【0】号产品
【0】号产品放入了缓冲容器
生产了【1】号产品
【1】号产品放入了缓冲容器
生产了【2】号产品
【2】号产品放入了缓冲容器
生产了【3】号产品
【3】号产品放入了缓冲容器
生产了【4】号产品
【4】号产品放入了缓冲容器
生产了【5】号产品
消费了【0】号产品
【5】号产品放入了缓冲容器
生产了【6】号产品
消费了【1】号产品
【6】号产品放入了缓冲容器
生产了【7】号产品
消费了【2】号产品
【7】号产品放入了缓冲容器
生产了【8】号产品
消费了【3】号产品
【8】号产品放入了缓冲容器
生产了【9】号产品
消费了【4】号产品
【9】号产品放入了缓冲容器
消费了【5】号产品
消费了【6】号产品
消费了【7】号产品
消费了【8】号产品
消费了【9】号产品

总结一下:

  1. ArrayBlockingQueue:是一个用数组实现的有界阻塞队列,此队列按照先进先出(FIFO)的原则对元素进行排序。支持公平锁和非公平锁。【注:每一个线程在获取锁的时候可能都会排队等待,如果在等待时间上,先获取锁的线程的请求一定先被满足,那么这个锁就是公平的。反之,这个锁就是不公平的。公平的获取锁,也就是当前等待时间最长的线程先获取锁】
  2. LinkedBlockingQueue:一个由链表结构组成的有界队列,此队列的长度为Integer.MAX_VALUE。此队列按照先进先出的顺序进行排序。注意一般使用LinkedBlockingQueue要设置容量,否则默认是Integer.MAX_VALUE,这样如果消费速度太慢,生产者一直往队列添加,导致内存撑爆。

BlockingQueue我就不想细说了,感觉个人理解有点欠缺,分享一个大神的博客吧,等我以后学懂了再写博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值