synchronized实现的生产者消费者模式

xiaoxiao2021-02-28  56

生产者-消费者

  一个或多个生产者创建某些工作并将其置于缓冲区或队列中,一个或多个消费者会从队列中获得这些工作并完成之。这里的缓冲区或队列是临界资源。当缓冲区或队列放满的时候,生产这会被阻塞;而缓冲区或队列为空的时候,消费者会被阻塞。生产者和消费者的调度是通过二者相互交换信号完成的

这里用到了线程的并发,和同步机制,同步锁lock的使用,wait,notify的使用:
代码如下:
package lockDemo; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class SynchronizedDemo { public static void main(String[] args) { //利用Lock接口和ReentrantLock类创建一个锁,作为对象唯一的标志,锁标志 Lock lock=new ReentrantLock(); //创建共享资源对象方法 Resource resource=new Resource("唛头", lock, 5); //创建生产者线程和消费者对象线程 Productor productor=new Productor(resource); Customer customer=new Customer(resource); Thread thread1=new Thread(productor, "SA"); Thread thread2=new Thread(customer, "SB"); //线程启动 thread1.start(); thread2.start(); } } class Resource{ private String name; private int count;//用来记录生产和消费后库存的馒头数 private boolean has=false;//保证count的安全性,数据准确性 private Lock lock;//锁对象 public Resource() {}//无参构造方法 public Resource(String name,Lock lock,int count) {//有参的构造方法,主要是传入锁对象 this.name=name; this.lock=lock; this.count=count; } //存放,生产者生产放入馒头的方法 public void push(int num) { while(true) {//保证循环执行 synchronized (lock) {//同步代码块和同步锁对象 lock.notifyAll();//唤醒所以其它正在等待该该锁的线程 if (!has && (count+num)>=20) {//双重判定保证数据准确 try { lock.wait();//让拥有该锁的对象睡眠,阻塞,注意必须用在同步块中 Thread.sleep(1000);//让当前线程睡眠1秒 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //这里将判断标志has至为原值,便于下一轮判断使用,避免因进入取走状态时候发生变化 has=false;//不可少 }else { count+=num; System.out.println(Thread.currentThread().getName()+"放入:"+num+" 个"); System.out.println("当前:"+count); //这里将判断标志has至为原值,便于下一轮判断使用 has=false; try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } //外取,消费者消费取走馒头方法 public void popup(int num) { while(true) { //这里用到has原因是为了避免两个线程都到了这里,并且此时has都是true是发生混乱 synchronized (lock) { lock.notifyAll(); if (has && (count-num)<=0) { try { lock.wait(); Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } has=true; }else { count-=num; System.out.println(Thread.currentThread().getName()+"取走:"+num+" 个"); System.out.println("剩余"+count); has=true; try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } //其它没用枷锁的方法,显示了同步锁不会影响其它没有共享资源的方法 public void show() { System.out.println("傻帽"); } } class Productor implements Runnable{ Resource resource; public Productor() {} public Productor(Resource resource) {this.resource=resource;} @Override public void run() { //进入这里时候是随机的,先执行哪个线程的不一定,但是即某一个线程而言,一定是先执行方法show(),然后在两个线程的push和popup之间切换 resource.show(); resource.push((int)(Math.random()*5+1)); } } class Customer implements Runnable{ Resource resource; public Customer() {} public Customer(Resource resource) {this.resource=resource;} @Override public void run() { //这里可以用while或for将方法包围,实现多次方法调用,也可以不用,因为方法本身带有循环题 resource.show();
//设置取走馒头的数量为随机的 int ran=(int)(Math.random()*5+1); resource.popup(ran); } }
//这里要注意的是同步锁一定要放在资源共享的区域,共享的对象,类中都行,同时要保证所得唯一性
转载请注明原文地址: https://www.6miu.com/read-54493.html

最新回复(0)