0%

Java虚拟银行

Virtual Bank

模拟银行的多线程程序,实现如下要求:

  1. 银行于某时刻开始营业,运行若干时间后下班,窗口最上方会显示营业或下班的信息。到了下班时间,不再产生新的客户,只将等待的客户处理完,然后银行关门。
  2. 营业期间有多名顾客随机地来银行存钱、取钱,顾客的原有存款金额是随机生成的,此次交易需要的时间以及交易金额也是随机生成的。不允许透支,若取钱时余额不足,则退出本次操作。在窗口显示当前客户的序号、交易时长、操作金额和余额;
  3. 只有一名工作人员提供服务,若顾客数为0,则进行等待;
  4. 每次存取钱,在窗口显示当前有多少顾客在等待,以及银行目前的金额;
  5. 银行处理完所有的交易,关门时再报告今日受理客户总数以及银行余额;
  6. 程序运行的过程中在控制台打印出今日所有的交易记录。

    自定义类型:

  • Customer:客户类;

  • CustomerLine:客户队列;

  • CustomerGen:客户生成器;

  • Teller:工作人员

  • MyWindow:银行信息窗口

  • VirtualBank:模拟银行(主程序)

    运行效果

    • avatar
    • avatar
    • avatar

主类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class VirtualBank{

public static void main(String[] args)throws Exception {
//银行交易显示窗口
MyWindow myWindow=new MyWindow();
myWindow.display();

//客户队列
CustomerLine line=new CustomerLine(50,myWindow);
CustomerGen gen=new CustomerGen(line,myWindow);

//银行工作人员
Teller teller=new Teller(line,myWindow);

gen.start();
teller.start();

//下班时间到了,不再接待客户
TimeUnit.SECONDS.sleep(5);
gen.exit = true;
TimeUnit.SECONDS.sleep(4);
teller.exit = true;

//处理完剩余业务,银行关门
TimeUnit.SECONDS.sleep(1);
myWindow.textField_5.setText("交易完毕");
System.out.println("剩余的业务处理完毕 银行剩余钱数:"+teller.total+" 今日受理客户总数:"+teller.num);

}

}

客户类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class Customer 
{
public int balance;//客户余额
public int time;//客户服务时长
public boolean deposit;//客户操作类型,如果为true则为存款,false为取款
public int money;//客户操作金额
public MyWindow w1;//银行窗口显示信息
public Customer(int balance,int time,int depos,int money,MyWindow w)
{
this.balance=balance;this.time=time;this.money=money;
w1=w;
if(depos==0)
{//存钱
deposit=true;
}
else
deposit=false;
}
public synchronized boolean withdrawal()
{//取钱
w1.textField_9.setText("时长:"+time);
if(balance<money)
{//余额不足
System.out.print("时长:"+time+" 原存款:"+balance);
w1.textField_2.setText("取款:"+money);
w1.textField_3.setText("余额:"+balance+"(不足)");
System.out.println(" 取款:"+money+",余额:"+balance+"(不足) 操作失败");
return false;//取钱失败
}
else{
System.out.print("时长:"+time+" 原存款:"+balance);
balance=balance-money;
w1.textField_2.setText("取款:"+money);
w1.textField_3.setText("余额:"+balance);
System.out.println(" 取款:"+money+",余额:"+balance+" 操作成功");
return true;//取钱成功
}
}

public synchronized void deposit()
{//存钱
System.out.print("时长:"+time+" 原存款:"+balance);
w1.textField_9.setText("时长:"+time);
balance+=money;
w1.textField_2.setText("存款:"+money);
w1.textField_3.setText("余额:"+balance);
System.out.println(" 存款"+money+",余额:"+balance);
}
}

客户队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*ArrayBlockingQueue:
A bounded blocking queue backed by an array. This queue orders elements FIFO (first-in-first-out).
Once created, the capacity cannot be changed.
Attempts to put an element into a full queue will result in the operation blocking;
attempts to take an element from an empty queue will similarly block.
*/
class CustomerLine extends ArrayBlockingQueue<Customer>
{//客户队列
public MyWindow w2;//银行窗口显示信息
public CustomerLine(int maxSize,MyWindow w)
{
super(maxSize);
w2=w;
}
}

随机产生客户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//随机产生顾客
class CustomerGen extends Thread
{
Random rand=new Random();
public boolean exit=false;//false表示银行仍在受理新来客户,可以继续产生客户
CustomerLine line;//客户队列
public MyWindow w3;//银行窗口显示信息
//得到顾客的队列
public CustomerGen(CustomerLine line,MyWindow w)
{
this.line=line;
w3=w;
}

public void run()
{
try
{//一直产生新的客户
while(!exit)
{
//随机时间里面产生顾客,产生的顾客需求也是随机地,客户的初始余额也是随机的
TimeUnit.MILLISECONDS.sleep(rand.nextInt(1000));
//然后队列里面添加一个随机地顾客
line.put(new Customer(rand.nextInt(1000),rand.nextInt(1000),rand.nextInt(2),rand.nextInt(1000),w3)); //随机的顾客需求
}
}
catch(InterruptedException e)
{
System.out.println("顾客线程出错!");
e.printStackTrace();
}

w3.textField.setText(" 下班时间到了");
System.out.println("\n工作人员要下班啦!不再受理新来客户\n");
}
}

工作人员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

//工作人员
class Teller extends Thread
{
public boolean exit=false;//false表示没有下班
public int num=0;//已服务的客户数
private CustomerLine line;//顾客队列
public int total=10000;//银行余额
public MyWindow w4;//银行窗口显示信息
public Teller(CustomerLine line,MyWindow w)
{
this.line=line;
w4=w;
}

public void run()
{
try
{
while(!exit)
{
if(line.size()==0)
{
//若没有客户,则进行等待
w4.textField_8.setText("0");
continue;
}
//Retrieves and removes the head of this queue,
//waiting if necessary until an element becomes available.
//队列里面排第一个的顾客脱离队伍,接受服务
Customer customer = line.take();
//这个要被服务的时间队列需要停顿,停顿时间有当前的customer决定
TimeUnit.MILLISECONDS.sleep(customer.time);

//显示顾客信息
if(customer.deposit)
{//存钱
customer.deposit();
total+=customer.money;
}
else
{//取钱
if(customer.withdrawal())
total-=customer.money;
}
w4.textField_6.setText(""+total);

//服务客户数量加一
// synchronized(this)
{
num++;
w4.textField_1.setText("第"+num+"位客户");
w4.textField_8.setText(""+line.size());
w4.textField_6.setText(""+total);
System.out.println("当前服务顾客数:"+num+",当前等待人数:"+line.size()+",银行余额:"+total);
System.out.println();
}
}
}
catch(InterruptedException e)
{
w4.textField_1.setText("银行服务线程出错!");
System.out.println("银行服务线程出错!");
e.printStackTrace();
}
}
}

银行窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//银行窗口
class MyWindow extends JFrame{
public static JPanel contentPane;
public static JTextField textField;//显示“上班时间”或“下班时间”
public static JTextField textField_1;//第几位客户
public static JTextField textField_2;//交易金额
public static JTextField textField_3;//客户余额
public static JTextField textField_4;
public static JTextField textField_5;//交易状态
public static JTextField textField_6;//银行余额
public static JTextField textField_7;
public static JTextField textField_8;//正在等待的人数
public static JTextField textField_9;//交易时长


/**
* Launch the application.
*/
public void display()throws Exception {
//显示窗口
MyWindow frame = new MyWindow();
frame.setVisible(true);
}

/**
* Create the frame.
*/
public MyWindow() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);

textField = new JTextField();
textField.setBackground(Color.PINK);
textField.setText(" 正在营业 ");
textField.setColumns(10);

textField_1 = new JTextField();
textField_1.setText("第0位客户");
textField_1.setColumns(10);

textField_2 = new JTextField();
textField_2.setText("交易:0");
textField_2.setColumns(10);

textField_3 = new JTextField();
textField_3.setText("余额:0");
textField_3.setColumns(10);

textField_4 = new JTextField();
textField_4.setText("银行余额");
textField_4.setColumns(10);

textField_5 = new JTextField();
textField_5.setBackground(Color.PINK);
textField_5.setText("正在交易");
textField_5.setColumns(10);

textField_6 = new JTextField();
textField_6.setText("0");
textField_6.setColumns(10);

textField_7 = new JTextField();
textField_7.setText("等待人数");
textField_7.setColumns(10);

textField_8 = new JTextField();
textField_8.setText("0");
textField_8.setColumns(10);

textField_9 = new JTextField();
textField_9.setText("时长:0");
textField_9.setColumns(10);

//布置文本框位置
GroupLayout gl_contentPane = new GroupLayout(contentPane);
gl_contentPane.setHorizontalGroup(
gl_contentPane.createParallelGroup(Alignment.LEADING)
.addGroup(gl_contentPane.createSequentialGroup()
.addGap(84)
.addComponent(textField, GroupLayout.PREFERRED_SIZE, 222, GroupLayout.PREFERRED_SIZE)
.addContainerGap(112, Short.MAX_VALUE))
.addGroup(gl_contentPane.createSequentialGroup()
.addGroup(gl_contentPane.createParallelGroup(Alignment.TRAILING, false)
.addGroup(gl_contentPane.createSequentialGroup()
.addGap(157)
.addComponent(textField_3))
.addGroup(Alignment.LEADING, gl_contentPane.createSequentialGroup()
.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
.addComponent(textField_7, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(textField_8, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addGap(61)
.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING, false)
.addComponent(textField_2)
.addComponent(textField_1, 0, 0, Short.MAX_VALUE)
.addComponent(textField_5, GroupLayout.DEFAULT_SIZE, 87, Short.MAX_VALUE)
.addComponent(textField_9))))
.addPreferredGap(ComponentPlacement.RELATED, 69, Short.MAX_VALUE)
.addGroup(gl_contentPane.createParallelGroup(Alignment.TRAILING, false)
.addComponent(textField_6)
.addComponent(textField_4)))
);
gl_contentPane.setVerticalGroup(
gl_contentPane.createParallelGroup(Alignment.LEADING)
.addGroup(gl_contentPane.createSequentialGroup()
.addComponent(textField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addGap(15)
.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
.addGroup(gl_contentPane.createSequentialGroup()
.addPreferredGap(ComponentPlacement.RELATED)
.addGroup(gl_contentPane.createParallelGroup(Alignment.LEADING)
.addGroup(gl_contentPane.createSequentialGroup()
.addGap(18)
.addComponent(textField_5, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.UNRELATED)
.addComponent(textField_1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(textField_9, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addGroup(gl_contentPane.createSequentialGroup()
.addGap(38)
.addComponent(textField_4, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(textField_6, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(textField_2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addGroup(gl_contentPane.createSequentialGroup()
.addGap(35)
.addComponent(textField_7, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addGap(18)
.addComponent(textField_8, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(textField_3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
contentPane.setLayout(gl_contentPane);
}
}