当同时有很多生产者和消费者往仓库里面增加产品减少产品,会产生以下两个问题:
1当生产者和消费者同时改变仓库对象的属性,最后打印出的结果不能反映仓库的情况
2当生产者过多或者消费者过多会使仓库满或者空,如果不把线程从运行态变成就阻塞态的话,会出现异常
解决方式:
问题1:在改变对象的方法加入同步锁,该方法运行时将对象或者对象的属性锁定,当方法运行完才可以访问该对象或者对象的属性
问题2:在方法头部加入判断条件,如果仓库满或空,则调用wait()方法。线程将交出对象锁,并进入阻塞状态。而当其他的生产或者消费方法执行过后,仓库不满或不空则调用notifyall()方法,将线程池中阻塞的方法变成就绪态。
下面我利用三种方法实现了生产者和消费者
方法一:
线程同步synchronized+线程通信wait(),notify()
import java.util.LinkedList;
import java.util.List;
/**
* Created by marsares on 15/7/7.
*/
public class ProducerAndCustomer1 {
public static void main(String[]args){
Storage storage=new Storage();
Producer1 p1=new Producer1(storage,"p1",10);
Producer1 p2=new Producer1(storage,"p2",10);
Producer1 p3=new Producer1(storage,"p3",10);
Producer1 p4=new Producer1(storage,"p4",10);
Producer1 p5=new Producer1(storage,"p5",10);
Customer1 c1=new Customer1(storage,"c1",10);
Customer1 c2=new Customer1(storage,"c2",10);
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
c1.start();
c2.start();
}
}
class Storage{
private static final int max=30;
private int size=0;
private int count=0;
LinkedList<String>storage=new LinkedList<String>();
public synchronized void add(int num){
notifyAll();
while(size+num>max){
System.out.println(Thread.currentThread().getName()+"wait for customer");
try{
wait();
}catch(InterruptedException e){
throw new RuntimeException(e);
}
}
for(int i=0;i<num;i++){
storage.add("apple" + count);
count++;
size++;
}
System.out.println(Thread.currentThread().getName()+" add "+num+" products,"+" size="+size);
}
public synchronized void delete(int num){
notifyAll();
while(size-num<0){
System.out.println(Thread.currentThread().getName()+"wait for producer");
try{
wait();
}catch(InterruptedException e){
throw new RuntimeException(e);
}
}
for(int i=0;i<num;i++){
storage.remove();
size--;
}
System.out.println(Thread.currentThread().getName()+" delete "+num+" products,"+" size="+size);
}
}
class Producer1 extends Thread{
Storage storage;
String name;
int num;
public Producer1(Storage storage,String name,int num){
this.storage=storage;
this.name=name;
this.num=num;
}
public void produce(int num){
storage.add(num);
}
public void run(){
produce(num);
}
}
class Customer1 extends Thread{
Storage storage;
String name;
int num;
public Customer1(Storage storage,String name,int num){
this.storage=storage;
this.name=name;
this.num=num;
}
public void consume(int num){
storage.delete(num);
}
public void run(){
consume(num);
}
}
方法二:
使用lock
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by marsares on 15/7/7.
*/
public class ProducerAndCustomer2 {
public static void main(String[]args){
Storage2 storage=new Storage2();
Producer2 p1=new Producer2(storage,"p1",10);
Producer2 p2=new Producer2(storage,"p2",10);
Producer2 p3=new Producer2(storage,"p3",10);
Producer2 p4=new Producer2(storage,"p4",10);
Producer2 p5=new Producer2(storage,"p5",10);
Customer2 c1=new Customer2(storage,"c1",10);
Customer2 c2=new Customer2(storage,"c2",10);
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
c1.start();
c2.start();
}
}
class Storage2{
private static final int max=30;
private int size=0;
private int count=0;
LinkedList<String> storage=new LinkedList<String>();
private final Lock lock=new ReentrantLock();
private final Condition full=lock.newCondition();
private final Condition empty=lock.newCondition();
public void add(int num){
lock.lock();
while(size+num>max){
System.out.println(Thread.currentThread().getName()+"wait for customer");
try{
full.await();
}catch(InterruptedException e){
throw new RuntimeException(e);
}
}
for(int i=0;i<num;i++){
storage.add("apple" + count);
count++;
size++;
}
System.out.println(Thread.currentThread().getName()+" add "+num+" products,"+" size="+size);
empty.signalAll();
lock.unlock();
}
public void delete(int num){
lock.lock();
while(size-num<0){
System.out.println(Thread.currentThread().getName()+"wait for producer");
try{
wait();
}catch(InterruptedException e){
throw new RuntimeException(e);
}
}
for(int i=0;i<num;i++){
storage.remove();
size--;
}
System.out.println(Thread.currentThread().getName()+" delete "+num+" products,"+" size="+size);
full.signalAll();
lock.unlock();
}
}
class Producer2 extends Thread{
Storage2 storage;
String name;
int num;
public Producer2(Storage2 storage,String name,int num){
this.storage=storage;
this.name=name;
this.num=num;
}
public void produce(int num){
storage.add(num);
}
public void run(){
produce(num);
}
}
class Customer2 extends Thread{
Storage2 storage;
String name;
int num;
public Customer2(Storage2 storage,String name,int num){
this.storage=storage;
this.name=name;
this.num=num;
}
public void consume(int num){
storage.delete(num);
}
public void run(){
consume(num);
}
}
方法三:
使用LinkedBlockingQueue
import java.util.concurrent.LinkedBlockingQueue;
/**
* Created by marsares on 15/7/7.
*/
public class ProducerAndCustomer3 {
public static void main(String[]args){
Storage3 storage=new Storage3();
Producer3 p1=new Producer3(storage,"p1",10);
Producer3 p2=new Producer3(storage,"p2",10);
Producer3 p3=new Producer3(storage,"p3",10);
Producer3 p4=new Producer3(storage,"p4",10);
Producer3 p5=new Producer3(storage,"p5",10);
Customer3 c1=new Customer3(storage,"c1",10);
Customer3 c2=new Customer3(storage,"c2",10);
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
c1.start();
c2.start();
}
}
class Storage3{
private static final int max=30;
private int size=0;
private int count=0;
LinkedBlockingQueue<String> storage=new LinkedBlockingQueue<String>(max);
public void add(int num){
for(int i=0;i<num;i++){
try{
storage.put("apple" + count);
count++;
size++;
}catch(InterruptedException e){
throw new RuntimeException(e);
}
}
System.out.println(Thread.currentThread().getName() + " add " + num + " products," + " size=" + size);
}
public void delete(int num){
for(int i=0;i<num;i++){
try{
storage.take();
size--;
}catch(InterruptedException e){
throw new RuntimeException(e);
}
}
System.out.println(Thread.currentThread().getName() + " delete " + num + " products," + " size=" + size);
}
}
class Producer3 extends Thread{
Storage3 storage;
String name;
int num;
public Producer3(Storage3 storage,String name,int num){
this.storage=storage;
this.name=name;
this.num=num;
}
public void produce(int num){
storage.add(num);
}
public void run(){
produce(num);
}
}
class Customer3 extends Thread{
Storage3 storage;
String name;
int num;
public Customer3(Storage3 storage,String name,int num){
this.storage=storage;
this.name=name;
this.num=num;
}
public void consume(int num){
storage.delete(num);
}
public void run(){
consume(num);
}
}