多线程—多生产者与多消费者 (if/while之间的区别)

  • Post author:
  • Post category:其他




引入

在这里插入图片描述

这是一个线程同步问题,生产者和消费者共享一个资源,并且生产者相互依赖,互为条件。

  • 对于生产者,没有生产产品之前,要通知消费者等待,生产了产品后,要通知消费者可以消费
  • 对于消费者,在消费之后,要通知生产者自己结束了消费,可以生产产品了

  • synchronized

    关键字可以阻止并发地更新同一个资源,可以实现同步,但是不能用来实现不同线程间的消息传递,也即是通信
wait 让线程一直等待,直到其它线程通知,会释放锁,可以传递一个类型为long的参数,表示指定等待的毫秒数
notify 唤醒一个处于等待状态的线程
notifyAll 唤醒同一个对象上所有调用wait方法的线程,优先级高的优先调度


上述方法均属于Object类的方法,只能在同步方法或者同步代码中使用,否则会抛出InterruptedException异常



并发协作模型“生产者/消费者模式” 管程法

  • 生产者:负责生产数据的模块
  • 消费者:负责处理数据的模块
  • 缓冲区:消费者不能直接使用生产者的数据,要通过缓冲区将生产者的数据放入到缓冲区中,消费者再从缓冲区里面拿出数据



缓冲区

class Container<T>{
    private LinkedList<T> list = new LinkedList<T>();
    private final int MAX = 100;
    private  int count = 0;

    //往缓冲区里面添加商品
    public synchronized void put(T t){
        while(list.size() == MAX){
            try{
                this.wait();;
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        list.add(t);
        System.out.println(Thread.currentThread().getName() + t);
        this.notifyAll();
    }
    
    //从缓冲区里面消费商品
    public synchronized void get()  {
        while (list.size() == 0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        String  t = (String) list.removeFirst();
        System.out.println(Thread.currentThread().getName() + t);
        this.notifyAll();
    }
}



消费者

class Customer implements Runnable{
    Container container;

    public Customer(Container container) {
        this.container = container;
    }

    @Override
    public void run() {
        while (true){
            container.get();
        }
    }
}



生产者

class Productor implements Runnable{
    Container container;
    String name;
    
    public Productor(Container container,String name) {
        this.container = container;
        this.name = name;
    }

    @Override
    public void run() {
        while (true){
            container.put(name);
        }
    }
}



主函数

public class testThread{
    public static void main(String[] args) {
    
        Container<String> container = new Container();
        
        new Thread(new Productor(container,"桃子"),"生产者1").start();
        new Thread(new Customer(container),"消费者1").start();
        new Thread(new Customer(container),"消费者2").start();
        new Thread(new Productor(container,"雪梨"),"生产者2").start();

    }
}



注意


在多生产者的情况下我们判断的时候要用


while


来做判断而不是

if

我们假设线程的调度是这样的,我们假设缓冲区最大容量为7,此时是已经达到最大容量,生产者线程都会被阻塞(此时生产者线程A已经经过


if


判断,在wait处等待,生产者线程B也通过了

if

判断,在wait处等待),当消费者通知生产者线程可以生产时(我们调用的是notifyAll方法),所有被阻塞的生产者线程都会被唤醒(A和B都会被唤醒),假如是生产者线程A获得了执行的机会,即获得了锁,而生产者线程B 继续在锁池中等待,

此时生产者线程B是醒着的

。假设生产者又把缓冲区生产满了,并且释放锁,生产者线程B获得锁,在这种情况下,B已经通过了

if

判断,即使缓冲区已经满了,但是B一样可以往里面添加数据,就会造成错误。假如我们用的是

while



版权声明:本文为weixin_43686867原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。