java基础之线程通信(生产者消费者模型)

博客介绍了线程通信的两种实现方式。一是通过 synchronized 关键字保证线程同步实现通信,工厂类采用单例模式;二是使用 ReentrantLock 类加锁的线程的 Condition 类的 await()/signal()/signalAll() 实现通信,这种方式更安全高效,推荐使用。

线程的生产者消费者模型一定是线程同步的,并且是统一工厂,这个可以用单例模式来实现,话不多说拉,直接代码演示,有可能存在不足,请留言告知!!!

1、 通过 synchronized 关键字保证线程同步来实现线程通信

工厂类,也就是容器,使用了单例模式

package cn.bzu.look.dao;

import java.util.ArrayList;

public class Warehouse {
	//定义一个集合来保存商品
	private ArrayList<String> arrayList = new ArrayList<>();
	//定义一个Warehouse的对象,私有的,
	private static Warehouse warehouse;

	private Warehouse() {
	}
	//单例模式,得到类的对象
	public static Warehouse getInstance() {
		if (warehouse == null) {
			warehouse = new Warehouse();
		}
		return warehouse;
	}

	public synchronized void get() {
		try {
			if (arrayList.size() < 3) {//
				this.wait();
			} else {
				System.out.println("超过3个,开始购买商品"+arrayList.size());
				arrayList.remove(0);
				System.out.println(arrayList.size());
				

			}
			notifyAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	public synchronized void add() {
		
		try {
			//如果集合中的元素大于五个元素,就进入等待
			if (arrayList.size() > 5) {
				this.wait();
			} else {
				//否则就添加元素
				System.out.println("不足五个,开始添加元素"+arrayList.size());
				arrayList.add("hengheng");
				System.out.println(arrayList.size());		
			}
			notifyAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}
}

生产者

package cn.bzu.look.dao;

public class Producer extends Thread {
	//
	private String producerName;
	//得到容器的实例对象
	Warehouse warehouse = Warehouse.getInstance();
	
	public String getProducerName() {
		return producerName;
	}
	//
	public void setProducerName(String producerName) {
		this.producerName = producerName;
	}

	public Producer(String producerName) {
		super();
		this.producerName = producerName;
	}
	
	@Override
	public void run() {
		int i = 0;
		while (i<10) {
		System.out.println(producerName + "开始生产产品");
			warehouse.add();
			try {
				//睡眠200毫秒
				Thread.sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			i++;
		}
	}

}

消费者

package cn.bzu.look.dao;

public class Consumer extends Thread {
	Warehouse warehouse = Warehouse.getInstance();
	private String consumerName;

	public String getConsumerName() {
		return consumerName;
	}

	public void setConsumerName(String consumerName) {
		this.consumerName = consumerName;
	}

	public Consumer(String consumerName) {
		super();
		this.consumerName = consumerName;
	}
	

	@Override
	public void run() {
		int i=0;
		while (i<10) {
		System.out.println(consumerName + "开始购买时商品");
			warehouse.get();	
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			i++;
		}
	}
}

测试类

package cn.bzu.look.dao;

public class ThreadTest {
	public static void main(String[] args) {
		Producer pro1 = new Producer("生产者1");
		Consumer con1 = new Consumer("消费者2");
		pro1.start();
		con1.start();
	}
}

结果,結果展示的不全

消费者2开始购买时商品
生产者1开始生产产品
不足五个,开始添加元素0
1
生产者1开始生产产品
不足五个,开始添加元素1
2
消费者2开始购买时商品
生产者1开始生产产品
不足五个,开始添加元素2
3
消费者2开始购买时商品
超过3个,开始购买商品3
2
生产者1开始生产产品
不足五个,开始添加元素2
3
消费者2开始购买时商品
超过3个,开始购买商品3
2
消费者2开始购买时商品
生产者1开始生产产品
不足五个,开始添加元素2
3
消费者2开始购买时商品
超过3个,开始购买商品3
2
生产者1开始生产产品
不足五个,开始添加元素2
3
2、 ReentrantLock类加锁的线程的Condition类的await()/signal()/signalAll()来实现通信

Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。
因此通常来说,线程通信的实现比较推荐使用Condition

  1. Condition是个接口,基本的方法就是await()和signal()方法;
  2. Condition依赖于Lock接口,生成一个Condition的基本代码是 lock.newCondition()
  3. 调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用
Conditon中的await()对应Object的wait();
Condition中的signal()对应Object的notify();
Condition中的signalAll()对应Object的notifyAll()

只改变Warehouse 类的内容,其他的类不变


public class Warehouse {
    //定义一个集合来保存商品
    private ArrayList<String> arrayList = new ArrayList<>();
    //定义一个Warehouse的对象,私有的,
    private static Warehouse warehouse;

    private Lock lock;

    private Condition condition;

    private Warehouse(Lock lock, Condition condition) {
        this.lock = lock;
        this.condition = condition;
    }


    //单例模式,得到类的对象
    public static Warehouse getInstance() {
        if (warehouse == null) {
            Lock lock = new ReentrantLock();
            Condition condition = lock.newCondition();
            warehouse = new Warehouse(lock,condition);
        }
        return warehouse;
    }

    public void get() {
        lock.lock();
        try {
            if (arrayList.size() < 3) {
                condition.await();
            } else {
                System.out.println("超过3个,开始购买商品" + arrayList.size());
                arrayList.remove(0);
                System.out.println(arrayList.size());
            }
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public  void add() {
        lock.lock();
        try {
            //如果集合中的元素大于五个元素,就进入等待
            if (arrayList.size() > 5) {
                condition.await();
            } else {
                //否则就添加元素
                System.out.println("不足五个,开始添加元素"+arrayList.size());
                arrayList.add("hengheng");
                System.out.println(arrayList.size());
            }
           condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

多线程的基础知识           https://blog.youkuaiyun.com/weixin_43610698/article/details/92800143

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值