问题背景:某人在银行里开设了账户,现在要模拟往这个银行里存钱和取钱的操作。
问题分析:这个问题里设计的变量有:
银行账户余额:当我们在账户余额操作时,出于安全以及现实的因素考虑,一个时候只能有一个动作访问这个账户余额。
涉及的动作有:
往银行里存钱:一次只能有一个人往银行里存钱,取钱动作不与存钱动作同时发生。
从银行里取钱:一次只能有一个人往银行里存钱,取钱不能与存钱的动作同时发生。
问题抽象:
账户余额是一个变量,且这个变量不能被两个不同的动作同时访问,因此它是临界资源(操作系统中的概念),若是执行对他的操作,必须是同步(线程协同工作, 按 照不同的顺序访问它)的。
存钱和取钱是两个动作,这两个动作在两个不同的线程中执行(计算机代码必须在一个线程中才能执行),由于这两个线程中的代码都需要访问账户这个变量,所以
这两个线程需要同步执行,即当我们的存钱线程在进行时(存钱线程被CPU调度),给临界资源加锁,当另外一个线程需要访问账户余额这个临街资源时,会先检查这个临界资源是否被“锁上了”,如果锁上了,就进入等待队列,等待这个“锁”被解除,一但这个锁被解除,上一个线程结束,等待队列里面的等待线程激活,进入执行状态,并再次给临界资源加锁,周而复始,直到所有线程执行完成。
如下是我的代码,其中不仅仅有关于线程的知识点,也有一些关于java堆栈的分析过程。
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class bankThread extends JFrame{
//在这里声明一些引用,相当于是声明了一些指针,作为总体变量,后面即使在不同的方
//法体中为他们申请实际内存(建立实例),也可以在整个实例中被访问
private JPanel contentpane;
private JTextArea textarea;
private JButton button;
private Font font=new Font("微软雅黑",Font.PLAIN,16);
/**
* the constructor
*/
public bankThread(){
setTitle("银行模拟器");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(400,400,400,400);
contentpane=new JPanel();
setContentPane(contentpane);
contentpane.setLayout(new GridLayout(3,1));
JLabel label=new JLabel("以下内容表示银行的存取过程");
label.setFont(font);
textarea = new JTextArea();
contentpane.add(textarea);
button=new JButton("开始模拟");
button.setFont(font);
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
do_button_action(e);
}
});
contentpane.add(label);
contentpane.add(textarea);
contentpane.add(button);
}
private class Bank {
private int account = 100;
//the method is used to add the money
public void addMoney(int money) {
synchronized (this) {// 获得Bank类的锁
account += money;
}
}
//the method is used to reduce money
public void reduceMoney(int money){
synchronized (this) {// 获得Bank类的锁
account += money;
}
}
public int getAccount() {
return account;
}
}
/**
* the program will be executed when you click the button
*/
protected void do_button_action(ActionEvent e){
Bank bank=new Bank();
Thread thread1 = new Thread(new Transfer(bank, 0));
thread1.start();
Thread thread2 = new Thread(new Transfer(bank, 1));
thread2.start();
}
private class Transfer implements Runnable{
//这个类用来对银行存款进行操作,但是银行的存款余额变量
//是在另一个方法中自定义的,因此,需要一个指向外部的指针
//从而在本方法中对其进行访问
private Bank bank;
private int flag;
public Transfer(Bank bank,int flag){
this.bank=bank;
this.flag=flag;
}
@Override
public void run() {
// TODO Auto-generated method stub
if(flag==1){
for(int i=0;i<10;i++){
bank.addMoney(10);
String text=textarea.getText();
textarea.setText(text+"账户余额是"+bank.getAccount());
}
}else if(flag==0){
for(int i=0;i<10;i++){
bank.reduceMoney(10);
String text=textarea.getText();
textarea.setText(text+"账户余额是"+bank.getAccount());
}
}
}
}
/**
* launch the application
*/
public static void main(String args[]){
bankThread frame=new bankThread();
frame.setVisible(true);
}
}