0
点赞
收藏
分享

微信扫一扫

生产者和消费者案例


生产者和消费者问题是一个经典的线程(进程)同步问题。他们之间有一个共用的缓存区,在缓存区为空时生产者生产物品投入缓存池,

缓存池非空的时候,消费者就可以从缓存池中取走物品。

SharedResource.java

package com._520it.day02._producer_consumer;

// 共享的资源
public class ShapedResource {
private String name ;
private String gender ;


synchronized public void push(String name , String gender ) {
this.name = name ;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.gender = gender ;
}
synchronized public void pop() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(this.name +"-"+this.gender);
}

}

Producer.java

package com._520it.day02._producer_consumer;
// 生产者
public class Producer implements Runnable{
private ShapedResource resource =null ;
public Producer(ShapedResource resource) {
this.resource = resource ;
}
public void run() {

for(int i = 0 ; i<50 ; i++ ) {
if(i %2 == 0 ) {

resource.push("张汉森", "男");
}
else {
resource.push("马浩峰","女") ;
}
}
}

}

Consumer.java

package com._520it.day02._producer_consumer;

public class Consumer implements Runnable{
private ShapedResource resource = null ;

public Consumer(ShapedResource resource) {
this.resource = resource ;
}
public void run() {
for(int i = 0 ; i<50 ;i++ ) {
resource.pop();
}
}
}

问题一 : 出现性别紊乱 

       解决方案: 只有保证生产姓名和性别过程保持同步,中间不能让消费者取走树

       使用同步代码块/同步方法/lock机制。

问题二 : 应该生产一个数据,消费一个数据

       解决方案: 得使用等待和唤醒机制。

同步锁池 : 

     同步锁必须选择多个线程共同的资源对象. 

     当生产者在生产数据的时候(先拥有同步锁),其他线程就在锁池中等待获取锁

     当线程执行问同步代码时,就会释放同步锁,其他线程就可以开始抢锁的使用权

线程通信-wait 和notify方法 :

java.lang.Object类提供类两类用于操作线程通信的方法。

wait(): 执行该方法的线程对象释放同步锁,jvm把该线程存放到等待池中,等待其他线程唤醒该线程。

notify() : 执行该方法的线程对象唤醒在等待池中的任意一个线程,把线程转到锁池中等待(等待被调度)。 

notifyAll(): 执行该方法的线程对象唤醒在等待池中的所有线程,把线程转到锁池中等待。

注意 :  上述方法只能被同步监听锁对象来调用,否则报错 

假设 A 线程和 B线程共同操作一个x对象(同步锁) ,A,B线程可以通过x对象的wait和 notify方法来进行通信。

流程 : 

  1.    当A线程执行x对象的同步方法时,A线程持有x对象的锁,B线程没有执行机会,B线程在x对象的锁池中等待。
  2.    A线程在同步方法中执行x.wait()方法时,A线程释放x对象的锁,进入x对象的等待池中。
  3.    在x 对象的锁池中等待的B线程获取到 x 对象的锁,执行x的另一个同步方法。
  4.    B线程在同步方法中执行x.notify () 方法时,jvm 把A线程从x对象的等待池中移动到x对象的锁池中,等待获取锁。
  5.    B线程执行完同步方法,释放A线程获取锁,继续上面流程。

 

修改 SharedResource.java

package com._520it.day02._producer_consumer;

// 共享的资源
public class ShapedResource {
private String name ;
private String gender ;
private boolean isEmpty = true;
// 表示共享资源对象是否为空

// 生产者生产资源
// synchroize 可以理解为线程互斥实现同步,在该线程进入资源区,其他线程只能等

synchronized public void push(String name , String gender ) {
try {
while(!isEmpty){ // 当不空时 ,等消费者来获取数据
this.wait(); // 生产完了,释放锁
// 使用同步锁对象来调用,表示当前进程释放同步锁,进入等待池
}
// 生成开始
this.name = name ;
Thread.sleep(10);
this.gender = gender ;
this.notify(); // 唤醒一个消费者
isEmpty = false ; // 现在共享资源中数据不为空了
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
// 消费者消费资源
synchronized public void pop() {
try {
while(isEmpty) {
this.wait();
}
// 消费开始
System.out.println(this.name +"-"+this.gender);
Thread.sleep(10);
// 消费结束
this.notify(); // 唤醒一个生产者
isEmpty = true ;
} catch (InterruptedException e) {

e.printStackTrace();
}

}

}

App.java

package com._520it.day02._producer_consumer;

// 测试类
public class App {
public static void main(String[] args) {
// 共享资源
ShapedResource resource = new ShapedResource() ;

new Thread(new Producer(resource)).start();
new Thread(new Consumer(resource)).start();
}
}

线程通信 -使用 lock 和Condition 接口 

wait和notify 方法只能被同步监听锁对象来调用,否则报错,那么,lock 机制根本没有同步锁,也就没有自动获取锁和自动释放锁的概念。因为没有同步锁,所以lock机制不能调用 wait 和 notify 方法。

解决方案 : java5中提供了 lock 机制的同时提供了处理lock机制的通信控制的 Condition 接口。

使用Lock 机制可以取代 synchroized 代码块和 synchroized 修饰

使用 Condition 接口对象的await , signal,signalAll 方法取代 Object 类中的 wait , notify ,notifyAll 方法。

package com._520it.day02._02_producer_consumer_lock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// 共享的资源
public class ShapedResource {
private String name ;
private String gender ;
private boolean isEmpty = true;
private final Lock lock = new ReentrantLock() ;
private Condition condition = lock.newCondition() ;
// 表示共享资源对象是否为空

// 生产者生产资源
// synchroize 可以理解为线程互斥实现同步,在该线程进入资源区,其他线程只能等

public void push(String name , String gender ) {

lock.lock(); // 加锁
try {
while(!isEmpty) {
condition.await();
}
this.name = name ;
Thread.sleep(10);
this.gender = gender ;
isEmpty = false ;
condition.signalAll();
}
catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock(); // 释放锁
}
}
// 消费者消费资源
public void pop() {
lock.lock(); // 加锁
try {
while(isEmpty) {
condition.await();
}
// 消费开始
System.out.println(this.name +"-"+this.gender);
Thread.sleep(10);
// 消费结束
isEmpty = true;
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
lock.unlock();
}

}

}

举报

相关推荐

0 条评论