昨天有人在群裡說瞭一個多線程售票的問題,當時沒怎麼註意,後來沒事就自己做瞭一下,開始還覺得應該很簡單,最後昨天都沒做出來,今天早上在床上突然思路開闊,起來就完成瞭,唉,感嘆啊,有時候還真的要睡睡,這種事情在我身上都發生好幾次瞭,每次都是睡覺起來問題就可以解決瞭,呵呵。。。
我模擬的是一個自動售票機,當然可能程序還又bug,但先考慮這麼多吧,我假設來買票的人是還算是個理性點的啊
模擬的是一臺機器,其他都是人來這臺機器買票,票是5元一張,買的時候可以說買多少張,然後給錢,程序自動售票並找零。顧客交瞭前後首先機器有個收錢的方法,這個方法是按照一定的原則來的,他會把錢按5、10、20、50、100分開來裝,但由於錢的分發很多,我就采用瞭一個比較簡單的機器會按從大到小來分錢,比如你給他55他就會分為50和5,你給35它就會氛圍20+10+5,給45就是2*20+5。這就是機器收錢分開裝瞭。
接著就是找零瞭,機器也有個找零的方法,根據要找的餘額來看機器裡面是否有相應的錢數,有就直接找瞭,沒有就還要等待,等另外有人來買票,有對應的錢瞭才可以找。比如你開始去買1張票,但你給瞭10元,剛開張,機器裡面沒有5元的票子,機器肯定找不出來,他就會讓你等,如果下一個人買票時候給瞭5元的票子,那麼機器就可以找你錢瞭,大致情況就是這樣啦。貼一下代碼吧,以後自己也可以看看,說不定哪天自己就不小心刪掉瞭。
機器代碼:
Java代碼
package com.thread;
import java.util.HashMap;
import java.util.Map;
public class TicketMachine {
private int ticket = 20;
private Map<String,Integer> balance = new HashMap<String,Integer>();
public final float TICKET_PRICE = 5.0F;
public float[] type = {5.0F , 10.0F , 20.0F , 50.0F , 100.0F};
public String[] strType={"五元" , "十元" , "二十元" , "五十元" , "一百元"};
public int getTicket(){
return ticket;
}
public void setTicket(int ticket){
this.ticket=ticket;
}
public Map getBalance(){
return this.balance;
}
//假設給的錢都是5的倍數
public void separate(float money){
//判斷money是否是5的倍數,不是就舍去個位數轉成5的倍數
float temp=money/5;
money=5*temp;
for(int i=0;i<this.type.length;i++){
if(money<=type[i]){ //票隻賣100以內
if(money==type[i]){
this.save(this.strType[i],1);
}else{
float temp1,temp2,temp3,temp4;
if((temp1=money/50)>0){
this.save(this.strType[3],(int)temp1);
money-=50*(int)temp1;
}
if((temp2=money/20)>0){
this.save(this.strType[2],(int)temp2);
money-=20*(int)temp2;
}
if((temp3=money/10)>0){
this.save(this.strType[1],(int)temp3);
money-=10*(int)temp3;
}
if((temp4=money/5)>0){
this.save(this.strType[0],(int)temp4);
money-=5*(int)temp4;
}
}
break;
}
}
}
//向balance一張一張的存錢
public void save(String str,int add){
Integer num= (Integer) this.getBalance().get(str);
if(num==null){
num=0;
}
this.balance.put(str, num+add);
}
//從balance中取錢找零
//sdel是應該減掉的數,它=del*type[str的地址],del是減去的次數
//如果失敗map應該要恢復原樣的
public float delete(String str,int del,float sdel,Map<String,Integer> tempMap){
Integer num= tempMap.get(str);
if(num==null||num<1){
return sdel;
}else{
if(num>del){
tempMap.put(str, num-del);
return 0.0F;
}else{
tempMap.put(str, 0);
int temp=0;
for(int i=0;i<this.strType.length;i++){
if(str.equals(strType[i])){
temp=i;
}
}
return this.type[temp]*(del-num);
}
}
}
public boolean change(float result){
//判斷money是否是5的倍數,不是就舍去個位數轉成5的倍數
float temp=result/5;
result=5*temp;
//操作的map隻是暫時的,如果返回的是false那麼要恢復到原來的
Map<String,Integer> tempMap = new HashMap<String, Integer>();
tempMap.putAll(this.balance);
for(int i=0;i<this.type.length;i++){
if(result<=type[i]){ //票隻賣100以內
if(result==type[i]){
result-=type[i];
result+=this.delete(this.strType[i],1,type[i],tempMap);
}else{
float temp1,temp2,temp3,temp4;
if((temp1=result/50)>0){
result-=50*(int)temp1;//應該減去這麼多的
result+=this.delete(this.strType[3],(int)temp1,50*(int)temp1,tempMap);//加上沒有減掉的
}
if((temp2=result/20)>0){
result-=20*(int)temp2;
result+=this.delete(this.strType[2],(int)temp2,20*(int)temp2,tempMap);
}
if((temp3=result/10)>0){
result-=10*(int)temp3;
result+=this.delete(this.strType[1],(int)temp3,10*(int)temp3,tempMap);
}
if((temp4=result/5)>0){
result-=5*(int)temp4;
result+=this.delete(this.strType[0],(int)temp4,10*(int)temp4,tempMap);
}
}
if(result==0.0){
this.balance=null;
this.balance=tempMap;
return true;
}else{
return false;
}
}
}
return false;
}
//售票
public synchronized void saleTicket(int count,float money){
float sum=count*this.TICKET_PRICE;//購買票需要總金額
float result=0.0F;//應找零
if(money<sum){
System.out.println(Thread.currentThread().getName()+"退還錢,對不起,你的金額不足買"+count+"張票");
return;
}else if(count>this.getTicket()){
System.out.println(Thread.currentThread().getName()+"退還錢,對不起,今天的票隻剩下"+this.getTicket()+"張瞭");
return;
}else{
this.separate(money);
result=money-sum;
}
if(result==0.0){
System.out.println(Thread.currentThread().getName()+"恭喜你買票成功,謝謝惠顧");
return;
}else{
if(this.change(result)){
System.out.println(Thread.currentThread().getName()+"應找你"+result+"元,請收好找零,歡迎下次惠顧");
}else{
Thread changeTask=new ChangeTask(this,result);//後臺找零程序
changeTask.setDaemon(true);//設置為後臺線程,需要在start之前
changeTask.start();
try {
System.out.println(Thread.currentThread().getName()+"請等待。。。");
this.wait();//暫停等待
System.out.println(Thread.currentThread().getName()+"對不起讓你久等瞭,現在有零錢瞭,應找你"+result+"元,歡迎下次惠顧");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
買票人:
Java代碼
package com.thread;
import java.util.Timer;
public class BuyTicket extends Thread{
//售票機
private TicketMachine machine;
//購票數
private int count;
//買票錢
private float money;
//姓名
//private String name;
public BuyTicket(){
}
public BuyTicket(TicketMachine machine, int count, float money,String name) {
super(name);
this.machine = machine;
this.count = count;
this.money = money;
//this.name = name;
System.out.println(name+":幫我買"+count+"張票");
}
public void run() {
machine.saleTicket(count, money);
}
}
對於那些找零機器裡沒錢找的找零線程代碼:
Java代碼
package com.thread;
public class ChangeTask extends Thread {
private TicketMachine machine;
private final float result;
public ChangeTask(TicketMachine machine,float result){
this.machine=machine;
this.result=result;
}
@Override
public void run() {
//System.out.println("找零任務線程運行瞭。。。");
while(true){
synchronized (machine) {
if(machine.change(result)){
machine.notifyAll();
//System.out.println("已經通知瞭");
break;
}
}
}
}
}
測試代碼瞭:
Java代碼
package com.thread;
public class Test {
public static void main(String[] args) {
TicketMachine machine=new TicketMachine();
BuyTicket buy1=new BuyTicket(machine,1,5.0F,"張三");
BuyTicket buy2=new BuyTicket(machine,3,15.0F,"李四");
BuyTicket buy3=new BuyTicket(machine,5,33.0F,"王五");
BuyTicket buy4=new BuyTicket(machine,6,50.0F,"趙六");
buy1.start();
buy2.start();
buy3.start();
buy4.start();
}
}
作者“l555iu”