生产者和消费者问题
- 要想买一辆汽车,先生产一台汽车。做一台卖一台 ,没有的话就生产 有的话不生产光卖。
一.基本做法(不加锁和加锁)
1.不加锁
- Car.java
public class Car {
private String name;
private String color;
public Car() {
super();
// TODO Auto-generated constructor stub
}
public Car(String name, String color) {
super();
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
// 生产汽车的方法
public void prodCar(String name, String color) {
//给对象赋值
this.name=name;
this.color=color;
}
// 销售汽车的方法
public void sellCar() {
System.out.println("汽车的名字是"+name+"汽车的颜色"+color);
}
}
- Customer.java
public class Customer implements Runnable{
//引入Car
Car car;
public Customer(Car car) {
super();
this.car = car;
}
public Customer() {
super();
// TODO Auto-generated constructor stub
}
//消费汽车
int count=1;
@Override
public void run() {
// TODO Auto-generated method stub
while(count<=100) {
count++;
car.sellCar();
//休眠一下
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
- Producer.java
public class Producer implements Runnable {
// 引用Car
Car car;
public Producer(Car car) {
super();
this.car = car;
}
public Producer() {
super();
// TODO Auto-generated constructor stub
}
int count = 1;
//实际生产汽车的方法
@Override
public void run() {
// TODO Auto-generated method stub
while (count <= 100) {
count++;
int num = new Random().nextInt(2);
if (num % 2 == 0) {
car.prodCar("奥迪", "黑色");
} else {
car.prodCar("宝马", "红色");
}
//休眠一下
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
- 主程序Test
public class Test {
public static void main(String[] args) {
//实例化Car
Car car=new Car();
//实例化runnable接口
Producer pd=new Producer(car);
Customer ct=new Customer(car);
//创建thread线程
Thread pt=new Thread(pd);
Thread tc=new Thread(ct);
//启动线程
pt.start();
tc.start();
}
}
出现的问题
- 消费者和生产者数据不统一 ;
- 没有生产就开始销售,导致消费的数据为null;
- 生产的对象的信息与消费到的信息不统一:奥迪—红色,null—黑色,宝马—黑色 ;
2.使用lock锁
- 给操作加上锁,使用重入锁或者synchrozed ;
- 在生产者和消费者对象中,run里面加入lock锁 ,避免数据不一致 ;
- 生产一次消费多次或没有生产就消费了,但是同一car对象的数据是一致的。
- Car.java
public class Car {
private String name;
private String color;
public Car() {
super();
// TODO Auto-generated constructor stub
}
public Car(String name, String color) {
super();
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
// 生产汽车的方法
public void prodCar(String name, String color) {
//给对象赋值
this.name=name;
this.color=color;
}
// 销售汽车的方法
public void sellCar() {
System.out.println("汽车的名字是"+name+"汽车的颜色"+color);
}
}
- Customer.java
public class Customer implements Runnable{
//引入Car
Car car;
public Customer(Car car) {
super();
this.car = car;
}
public Customer() {
super();
// TODO Auto-generated constructor stub
}
//消费汽车
int count=1;
//创建锁
ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
// TODO Auto-generated method stub
while(count<=100) {
//加锁
lock.lock();
count++;
car.sellCar();
//休眠一下
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//释放锁
lock.unlock();
}
}
- Producer.java
public class Producer implements Runnable {
// 引用Car
Car car;
public Producer(Car car) {
super();
this.car = car;
}
public Producer() {
super();
// TODO Auto-generated constructor stub
}
int count = 1;
//创建锁
ReentrantLock lock=new ReentrantLock();
//实际生产汽车的方法
@Override
public void run() {
// TODO Auto-generated method stub
while (count <= 100) {
//加锁
lock.lock();
count++;
int num = new Random().nextInt(2);
if (num % 2 == 0) {
car.prodCar("奥迪", "黑色");
} else {
car.prodCar("宝马", "红色");
}
//休眠一下
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//解锁
lock.unlock();
}
}
}
- Test.java
public class Test {
public static void main(String[] args) {
//实例化Car
Car car=new Car();
//实例化runnable接口
Producer pd=new Producer(car);
Customer ct=new Customer(car);
//创建thread线程
Thread pt=new Thread(pd);
Thread tc=new Thread(ct);
//启动线程
pt.start();
tc.start();
}
}
二.使用 object的等待唤醒机制
- 先生产后消费,程序启动之后要先进行生产操作,后面在进行消费操作 重复此种循环操作。
- wait将当前操作进入阻塞状态;
- notify唤醒正在阻塞中的线程.
- Car.java
public class Car {
private String name;
private String color;
public Car() {
super();
// TODO Auto-generated constructor stub
}
public Car(String name, String color) {
super();
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
boolean flag=true;//true表示需要生产汽车了,false表示需要销售了
//生产汽车的方法
public synchronized void prodCar(String name, String color) {
if(!flag) {//不要生产
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//给对象赋值
this.name=name;
this.color = color;
System.out.println("生产一台汽车");
System.out.println("==================");
flag=false;//已经生产了汽车,需要进入等待销售操作
notify();//唤醒之前的销售被阻塞的状态
}
//销售汽车的方法
public synchronized void sellCar() {
//程序启动之后要先生产
if (flag) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("消费了一台汽车");
System.out.println("汽车的名字是"+name+"汽车的颜色"+color);
System.out.println("**********************");
flag=true;//消费完了需要再次等待了
notify();//唤醒之前等待的线程,就是生产汽车的线程
}
}
- Customer.java
public class Customer implements Runnable{
//引入Car
Car car;
public Customer(Car car) {
super();
this.car = car;
}
public Customer() {
super();
// TODO Auto-generated constructor stub
}
//消费汽车
int count=0;
@Override
public void run() {
// TODO Auto-generated method stub
while(count<=100) {
count++;
car.sellCar();
}
}
}
- Producer.java
public class Producer implements Runnable{
//引用Car
Car car;
public Producer(Car car) {
super();
this.car = car;
}
public Producer() {
super();
// TODO Auto-generated constructor stub
}
int count=0;
@Override
public void run() {
// TODO Auto-generated method stub
while(count<=100) {
count++;
int num=new Random().nextInt(2);
if(num%2==0) {
car.prodCar("奥迪", "黑色");
}else {
car.prodCar("宝马", "红色");
}
}
}
}
- Test.java
public class Test {
public static void main(String[] args) {
//实例化Car
Car car=new Car();
//实例化runnable接口
Producer pd=new Producer(car);
Customer ct=new Customer(car);
//创建thread线程
Thread pt=new Thread(pd);
Thread tc=new Thread(ct);
//启动线程
pt.start();
tc.start();
}
}
wait将当前线程进入阻塞状态,当遇到notify的时候,会再次唤醒wait线程。程序继续从我们的wait位置运行。