Java多线程 生产者消费者模型实例详解
生产者消费者模型
生产者:生产任务的个体;
消费者:消费任务的个体;
缓冲区:是生产者和消费者之间的媒介,对生产者和消费者解耦。
当
缓冲区元素为满,生产者无法生产,消费者继续消费;
缓冲区元素为空,消费者无法消费,生产者继续生产;
wait()/notify()生产者消费者模型
制作一个简单的缓冲区ValueObject,value为空表示缓冲区为空,value不为空表示缓冲区满
publicclassValueObject{ publicstaticStringvalue=""; }
生产者,缓冲区满则wait(),不再生产,等待消费者notify(),缓冲区为空则开始生产
publicclassProducer{ privateObjectlock; publicProducer(Objectlock) { this.lock=lock; } publicvoidsetValue() { try { synchronized(lock) { if(!ValueObject.value.equals("")) lock.wait(); Stringvalue=System.currentTimeMillis()+"_"+System.nanoTime(); System.out.println("Set的值是:"+value); ValueObject.value=value; lock.notify(); } } catch(InterruptedExceptione) { e.printStackTrace(); } } }
消费者,缓冲区为空则wait(),等待生产者notify(),缓冲区为满,消费者开始消费
publicclassCustomer{ privateObjectlock; publicCustomer(Objectlock) { this.lock=lock; } publicvoidgetValue() { try { synchronized(lock) { if(ValueObject.value.equals("")) lock.wait(); System.out.println("Get的值是:"+ValueObject.value); ValueObject.value=""; lock.notify(); } } catch(InterruptedExceptione) { e.printStackTrace(); } } }
main方法,启动一个生产者和一个消费者
publicclassMain{ publicstaticvoidmain(String[]args) { Objectlock=newObject(); finalProducerproducer=newProducer(lock); finalCustomercustomer=newCustomer(lock); RunnableproducerRunnable=newRunnable() { publicvoidrun() { while(true) { producer.setValue(); } } }; RunnablecustomerRunnable=newRunnable() { publicvoidrun() { while(true) { customer.getValue(); } } }; ThreadproducerThread=newThread(producerRunnable); ThreadCustomerThread=newThread(customerRunnable); producerThread.start(); CustomerThread.start(); } }
运行结果如下
Set的值是:1564733938518_27520480474279 Get的值是:1564733938518_27520480474279 Set的值是:1564733938518_27520480498378 Get的值是:1564733938518_27520480498378 Set的值是:1564733938518_27520480540254 Get的值是:1564733938518_27520480540254 ······
生产者和消费者交替运行,生产者生产一个字符串,缓冲区为满,消费者消费一个字符串,缓冲区为空,循环往复,满足生产者/消费者模型。
await()/signal()生产者/消费者模型
缓冲区
publicclassValueObject{ publicstaticStringvalue=""; }
ThreadDomain48继承ReentrantLock,set方法生产,get方法消费
publicclassThreadDomain48extendsReentrantLock { privateConditioncondition=newCondition(); publicvoidset() { try { lock(); while(!"".equals(ValueObject.value)) condition.await(); ValueObject.value="123"; System.out.println(Thread.currentThread().getName()+"生产了value,value的当前值是"+ValueObject.value); condition.signal(); } catch(InterruptedExceptione) { e.printStackTrace(); } finally { unlock(); } } publicvoidget() { try { lock(); while("".equals(ValueObject.value)) condition.await(); ValueObject.value=""; System.out.println(Thread.currentThread().getName()+"消费了value,value的当前值是"+ValueObject.value); condition.signal(); } catch(InterruptedExceptione) { e.printStackTrace(); } finally { unlock(); } } }
MyThread41启动两个生产线程和一个消费线程
publicclassMyThread41{ publicstaticvoidmain(String[]args) { finalThreadDomain48td=newThreadDomain48(); RunnableproducerRunnable=newRunnable() { publicvoidrun() { for(inti=0;i输出结果如下
Producer1生产了value,value的当前值是123 Consumer消费了value,value的当前值是 Producer1生产了value,value的当前值是123为什么Producer2无法生产,消费者无法消费呢?是因为此时缓冲区为满,Producer1的notify()应该唤醒Consumer却唤醒了Producer2,导致Producer2因为缓冲区为满和Consumer没有被唤醒而处于waiting状态,此时三个线程均在等待,出现了假死。
解决方案有两种:
1.让生产者唤醒所有线程,在set方法中使用condition.signalAll();
2.使用两个Condition,生产者Condition和消费者Condition,唤醒指定的线程;
正常输入如下:
······ Producer2生产了value,value的当前值是123 Consumer消费了value,value的当前值是 Producer2生产了value,value的当前值是123 Consumer消费了value,value的当前值是 Producer2生产了value,value的当前值是123 Consumer消费了value,value的当前值是 Producer1生产了value,value的当前值是123 Consumer消费了value,value的当前值是 Producer1生产了value,value的当前值是123 Consumer消费了value,value的当前值是 Producer1生产了value,value的当前值是123 Consumer消费了value,value的当前值是 Producer1生产了value,value的当前值是123 Consumer消费了value,value的当前值是 Producer1生产了value,value的当前值是123 Consumer消费了value,value的当前值是 ······以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。