Java多線程模擬銀行系統(tǒng)存錢問題詳解
一、題目描述
題目:模擬一個簡單的銀行系統(tǒng),使用兩個不同的線程向同一個賬戶存錢。
實現(xiàn):使用特殊域變量volatile實現(xiàn)同步。
二、解題思路
創(chuàng)建一個類:SynchronizedBankFrame,繼承JFrame類
寫一個內(nèi)部類Bank
- 定義一個account變量,來表示賬戶。
- deposit():一個存錢的方法
- getAccount():顯示賬戶余額的方法。
寫一個內(nèi)部類Transfer,實現(xiàn)Runnable接口
在run方法中實現(xiàn)向賬戶存錢的功能。
volatile關(guān)鍵字為變量訪問提供了一種免鎖機制。使用volatile關(guān)鍵字修飾變量,每次使用該變量就要重新計算,而不是使用寄存器中的值。
volatile不會提供原子操作,也不能用來修飾final類型的變量。
三、代碼詳解
SynchronizedBankFrame
package com.xiaoxuzhu;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridLayout;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Font;
import javax.swing.UIManager;
/**
* Description:
*
* @author xiaoxuzhu
* @version 1.0
*
* <pre>
* 修改記錄:
* 修改后版本 修改人 修改日期 修改內(nèi)容
* 2022/5/14.1 xiaoxuzhu 2022/5/14 Create
* </pre>
* @date 2022/5/14
*/
public class SynchronizedBankFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 2671056183299397274L;
private JPanel contentPane;
private JTextArea thread1TextArea;
private JTextArea thread2TextArea;
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Throwable e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SynchronizedBankFrame frame = new SynchronizedBankFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public SynchronizedBankFrame() {
setTitle("使用volatile實現(xiàn)線程同步");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
JPanel buttonPanel = new JPanel();
contentPane.add(buttonPanel, BorderLayout.SOUTH);
JButton startButton = new JButton("開始存錢");
startButton.setFont(new Font("微軟雅黑", Font.PLAIN, 16));
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
do_button_actionPerformed(arg0);
}
});
buttonPanel.add(startButton);
JPanel processPanel = new JPanel();
contentPane.add(processPanel, BorderLayout.CENTER);
processPanel.setLayout(new GridLayout(1, 2, 5, 5));
JPanel thread1Panel = new JPanel();
processPanel.add(thread1Panel);
thread1Panel.setLayout(new BorderLayout(0, 0));
JLabel thread1Label = new JLabel("一號線程");
thread1Label.setFont(new Font("微軟雅黑", Font.PLAIN, 16));
thread1Label.setHorizontalAlignment(SwingConstants.CENTER);
thread1Panel.add(thread1Label, BorderLayout.NORTH);
JScrollPane thread1ScrollPane = new JScrollPane();
thread1Panel.add(thread1ScrollPane, BorderLayout.CENTER);
thread1TextArea = new JTextArea();
thread1TextArea.setFont(new Font("微軟雅黑", Font.PLAIN, 16));
thread1ScrollPane.setViewportView(thread1TextArea);
JPanel thread2Panel = new JPanel();
processPanel.add(thread2Panel);
thread2Panel.setLayout(new BorderLayout(0, 0));
JLabel thread2Label = new JLabel("二號線程");
thread2Label.setFont(new Font("微軟雅黑", Font.PLAIN, 16));
thread2Label.setHorizontalAlignment(SwingConstants.CENTER);
thread2Panel.add(thread2Label, BorderLayout.NORTH);
JScrollPane thread2ScrollPane = new JScrollPane();
thread2Panel.add(thread2ScrollPane, BorderLayout.CENTER);
thread2TextArea = new JTextArea();
thread2TextArea.setFont(new Font("微軟雅黑", Font.PLAIN, 16));
thread2ScrollPane.setViewportView(thread2TextArea);
}
protected void do_button_actionPerformed(ActionEvent arg0) {
Bank bank = new Bank();
Thread thread1 = new Thread(new Transfer(bank, thread1TextArea));
thread1.start();
Thread thread2 = new Thread(new Transfer(bank, thread2TextArea));
thread2.start();
}
private class Transfer implements Runnable {
private Bank bank;
private JTextArea textArea;
public Transfer(Bank bank, JTextArea textArea) {
this.bank = bank;
this.textArea = textArea;
}
public void run() {
for (int i = 0; i < 10; i++) {
bank.deposit(10);
String text = textArea.getText();
textArea.setText(text + "賬戶的余額是:" + bank.getAccount() + "\n");
}
}
}
private class Bank {
private volatile int account = 100;// 將域變量用volatile修飾
public void deposit(int money) {// 向賬戶中存錢
account += money;
}
public int getAccount() {// 獲得賬戶余額
return account;
}
}
}

多學(xué)一個知識點
每個線程是存在緩存內(nèi)存的。且緩存內(nèi)存是對其他線程不可見的。這就是內(nèi)存不可見問題。

來驗證下
package com.xiaoxuzhu;
/**
* Description: 證明線程是存在緩存內(nèi)存的
*
* @author xiaoxuzhu
* @version 1.0
*
* <pre>
* 修改記錄:
* 修改后版本 修改人 修改日期 修改內(nèi)容
* 2022/5/14.1 xiaoxuzhu 2022/5/14 Create
* </pre>
* @date 2022/5/14
*/
public class VolatileDemo {
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();
//啟動線程 改值
new Thread(threadDemo).start();
while (true){
if(threadDemo.isFlag()){
System.out.println("主線程讀到的flag是true");
break;
}
}
}
static class ThreadDemo implements Runnable{
private boolean flag = false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag 線程執(zhí)行改為:"+isFlag());
}
}
}
主線程得到的是false,新線程已經(jīng)把值修改為true了。證實每個線程是存在緩存內(nèi)存的

到此這篇關(guān)于Java多線程模擬銀行系統(tǒng)存錢問題詳解的文章就介紹到這了,更多相關(guān)Java多線程銀行存錢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot Mybatis批量插入Oracle數(shù)據(jù)庫數(shù)據(jù)
這篇文章主要介紹了SpringBoot Mybatis批量插入Oracle數(shù)據(jù)庫數(shù)據(jù),文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08
SpringCloud?中防止繞過網(wǎng)關(guān)請求直接訪問后端服務(wù)的解決方法
這篇文章主要介紹了SpringCloud中如何防止繞過網(wǎng)關(guān)請求直接訪問后端服務(wù),本文給大家分享三種解決方案,需要的朋友可以參考下2023-06-06
ElasticSearch6.2.3+head插件安裝的方法步驟
這篇文章主要介紹了ElasticSearch6.2.3+head插件安裝的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
Java 中jasperReport實現(xiàn)動態(tài)列打印的實現(xiàn)代碼
這篇文章主要介紹了Java 中jasperReport實現(xiàn)動態(tài)列打印的實現(xiàn)代碼的相關(guān)資料,希望通過本文大家能掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09
springboot?ConfigurationProperties的綁定源碼示例解析
這篇文章主要為大家介紹了springboot?ConfigurationProperties的綁定源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
java工具類之實現(xiàn)java獲取文件行數(shù)
這篇文章主要介紹了一個java工具類,可以取得當(dāng)前項目中所有java文件總行數(shù),代碼行數(shù),注釋行數(shù),空白行數(shù),需要的朋友可以參考下2014-03-03

