问题背景:某人在银行里开设了账户,现在要模拟往这个银行里存钱和取钱的操作。
问题分析:这个问题里设计的变量有:
银行账户余额:当我们在账户余额操作时,出于安全以及现实的因素考虑,一个时候只能有一个动作访问这个账户余额。
涉及的动作有:
往银行里存钱:一次只能有一个人往银行里存钱,取钱动作不与存钱动作同时发生。
从银行里取钱:一次只能有一个人往银行里存钱,取钱不能与存钱的动作同时发生。
问题抽象:
账户余额是一个变量,且这个变量不能被两个不同的动作同时访问,因此它是临界资源(操作系统中的概念),若是执行对他的操作,必须是同步(线程协同工作, 按 照不同的顺序访问它)的。
存钱和取钱是两个动作,这两个动作在两个不同的线程中执行(计算机代码必须在一个线程中才能执行),由于这两个线程中的代码都需要访问账户这个变量,所以
这两个线程需要同步执行,即当我们的存钱线程在进行时(存钱线程被CPU调度),给临界资源加锁,当另外一个线程需要访问账户余额这个临街资源时,会先检查这个临界资源是否被“锁上了”,如果锁上了,就进入等待队列,等待这个“锁”被解除,一但这个锁被解除,上一个线程结束,等待队列里面的等待线程激活,进入执行状态,并再次给临界资源加锁,周而复始,直到所有线程执行完成。
如下是我的代码,其中不仅仅有关于线程的知识点,也有一些关于java堆栈的分析过程。
package practice34; 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); } }