题目一
桌子上有一空盘,最多允许存放一只水果,爸爸可向盘中放一个苹果或一个桔子,儿子专等吃盘中的桔子
女儿等吃苹果
思路分析
1)总体来看,适合用消费者和生产者模式来解决该问题。爸爸放水果,为生产者,儿子和女儿则是两个消费者,或者是同意消费者的两种消费形式。
2)如果单纯建立Father和Children直接实现Runnable接口来完成题目,会发现这两个线程之间是需要通信的,需要在Father类中提供Children引用才能操作Children,同理Children也得提供Father引用,这样操作太繁琐,我们引用Dish中间对象,这样操作变得简单了。
问题分析
1)线程不同步问题。我们需要的是生产一个水果,消费一个水果,不能一直生产,或者连续消费。所以我们可以设置isEmpty的boolean变量,来判断盘子内是否为空,如果为空,则消费者线程休眠,唤醒生产者线程。若盘子不为空,我们则让消费者唤醒,生产者休眠。
2)保证线程同步有两种方法,一种是利用synchronized机制,this.wait()和this.notify()方法来操作,第二种是利用lock机制,和condition接口的await()和signal方法来操作。
Father.java
public class Father implements Runnable{
Dish dish = null;
Father(Dish dish){
this.dish = dish;
}
public void run() {
for(int i=0;i<50;i++){
if(i%5==0)
dish.push("apple");
else
dish.push("orange");
}
}
}
Children.java
public class Children implements Runnable{
Dish dish = null;
Children(Dish dish){
this.dish = dish;
}
public void run(){
for(int i=0;i<50;i++){
dish.pop();
}
}
}
Dish.java
public class Dish {
private String fruit;
private boolean isEmpty=true;
/**
* 生产水果
*/
synchronized public void push(String fruit){
try{
if(!isEmpty){
this.wait();
}
this.fruit = fruit;
isEmpty = false;
this.notifyAll();
}catch(Exception e){}
}
/**
* 消费水果
*/
synchronized public void pop(){
try{
if(isEmpty){
this.wait();
}
if("apple".equals(fruit))
System.out.println("儿子吃了"+fruit);
if("orange".equals(fruit))
System.out.println("女儿吃了"+fruit);
isEmpty = true;
this.notifyAll();
}catch(Exception e){}
}
}
MainDemo.java
public class MainDemo {
public static void main(String[] args) {
Dish dish = new Dish();
new Thread(new Father(dish)).start();
new Thread(new Children(dish)).start();
}
}
题目二
有一个仓库,可以存放A和B两种产品,但要求:
2.-N<A产品数量-B产品数量<M
其中N和M都是正整数,请实现A和B产品入库的操作
解析:
1)method1()方法是利用生产者-消费者模式进行输出,即交替输出入库信息,入库A接着入库B
2)method2()方法时利用题目要求对A和B的数量差限制来输出,只有满足条件才能显示入库
3)本题目亮点在于同一类的两种线程调用同一个方法如何实现线程同步
亮点分析
一进入方法就唤醒下一个线程,执行完后在休眠本线程,不用通过设置boolean值来完成操作
lock.lock();//获取锁
condition.signalAll();
System.out.println("现在入库第 "+ ++count+" 件产品"+"-产品名称:"+productName);
Thread.sleep(100);
condition.await();
Product.java
public class Product implements Runnable {
private String name;//产品名称
WareHouse WareHouse = null;
Product(String name,WareHouse wareHouse){
this.name=name;
this.WareHouse = wareHouse;
}
public void run(){
for(int i=0;i<100;i++){
WareHouse.importWareHouse(name);
}
}
}
WareHouse.java
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class WareHouse {
private final int N = 20;//常数M代表20
private final int M = 20;//常数N代表20
private int count = 0;//用来计数仓库的第几个货物
private int Acount =0;
private int Bcount =0;
private final Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean isEmpty = true;//保证只能存一个
private String productName;//产品名称
/**
* 入库操作
*/
public void importWareHouse(String productName){
//method1(productName);//消费者-生产者模式
method2(productName);
}
private void method2(String productName) {
try{
lock.lock();//获取锁
if("A".equals(productName))
Acount++;
if("B".equals(productName))
Bcount++;
if(Acount-Bcount>-N && Acount-Bcount<M){
System.out.println("现在入库第 "+ ++count+" 件产品"+"-产品名称:"+productName);
}
System.out.println(Acount-Bcount);
Thread.sleep(100);
}catch(Exception e){}
finally{
lock.unlock();//释放锁子
}
}
private void method1(String productName){
try{
lock.lock();//获取锁
condition.signalAll();
System.out.println("现在入库第 "+ ++count+" 件产品"+"-产品名称:"+productName);
Thread.sleep(100);
condition.await();
}catch(Exception e){}
finally{
lock.unlock();//释放锁子
}
}
}
MainDemo.java
public class MainDemo {
public static void main(String[] args) {
WareHouse wareHouse = new WareHouse();
new Thread(new Product("A",wareHouse)).start();
new Thread(new Product("B",wareHouse)).start();
}
}