Question: simulates bank withdrawals and uses three thread synchronization methods to ensure the security of withdrawals. Write the following classes and perform a withdrawal test:
Account type: Account, including the balance Field balance
Withdrawal class: DrawMoney, which can be used to withdraw money from a specified account.
Write thread body: security of withdrawal operations
Method 1: Synchronize code blocks
/*** Bank Account */class Account {/*** balance */private double balance;/*** constructor * @ param balance */Account (double balance) {super (); this. balance = balance;} // getter. setterpublic double getBalance () {return balance;} public void setBalance (double balance) {this. balance = balance ;}} class ATM implements Runnable {/*** amount to be retrieved */private double drawMoney; String str = new String (""); // listening object for Synchronous Code blocks/*** account */priv Ate Account a; ATM (double drawMoney, Account a) {super (); this. drawMoney = drawMoney; this. a = a;} public void run () {synchronized (str) {if (. getBalance ()> = drawMoney) {System. out. println (Thread. currentThread (). getName () + "spit out" + drawMoney + "Yuan");. setBalance (. getBalance ()-drawMoney); // modify balance} else {System. out. println ("Your account don't have enough money! ") ;}}} Public class DrawMoneyDemo {public static void main (String [] args) {Account a = new Account (1000); ATM atm = new ATM (800, a); // get 800 yuan from account a // assume there are two threads simultaneously operating new Thread (atm, ""). start (); new Thread (atm, "B "). start ();}}
The execution result is:
B spit out 800.0 yuan
Your account don't have enough money!
We put atomic code into the synchronized code block to form a synchronous code block. In this way, at the same time, only one thread can enter the code block to execute the code segment.
Format:
Synchronized (object ){
// Code block
}
Method 2: Synchronization Method
Define a synchronous method in the account class to implement the withdrawal operation, so that the method can only be called mutex upon thread execution.
/*** Bank Account */class Account {/*** balance */private double balance;/*** constructor ** @ param balance */Account (double balance) {super (); this. balance = balance;} // getter. setterpublic double getBalance () {return balance;} public void setBalance (double balance) {this. balance = balance;}/*** use the synchronous method to withdraw money * @ param drawMoney * Withdrawal amount */public synchronized void draw (double drawMoney) {if (this. getBalance ()> = dr AwMoney) {System. out. println (Thread. currentThread (). getName () + "spit out" + drawMoney + "Yuan"); this. setBalance (this. getBalance ()-drawMoney); // modify balance} else {System. out. println ("Your account don't have enough money! ") ;}}} Class ATM implements Runnable {/*** amount to be obtained */private double drawMoney;/*** Account */private Account; ATM (double drawMoney, Account a) {super (); this. drawMoney = drawMoney; this. a = a;} public void run () {. draw (drawMoney) ;}} public class DrawMoneyDemo {public static void main (String [] args) {Account a = new Account (1000); ATM atm = new ATM (800, a); // get 800 yuan from account a // assume there are two threads simultaneously operating new Thread (atm, ""). start (); new Thread (atm, "B "). start ();}}
The execution result is:
A spit out 800.0 yuan
Your account don't have enough money!
Method 3: Use the synchronization lock mechanism of Java 5 to implement Thread Synchronization
Import java. util. concurrent. locks. reentrantLock;/***** bank Account */class Account {/***** balance */private double balance; // defines the reentrant lock private final ReentrantLock lock = new ReentrantLock (); /*** constructor ** @ param balance */Account (double balance) {super (); this. balance = balance;} // getter. setterpublic double getBalance () {return balance;} public void setBalance (double balance) {this. balance = balance;}/*** use the reentrant lock * @ Param drawMoney * Withdrawal amount */public void draw (double drawMoney) {lock. lock (); // lock try {if (this. getBalance ()> = drawMoney) {System. out. println (Thread. currentThread (). getName () + "spit out" + drawMoney + "Yuan"); this. setBalance (this. getBalance ()-drawMoney); // modify balance} else {System. out. println ("Your account don't have enough money! ") ;}} Finally {lock. unlock (); // release lock} class ATM implements Runnable {/*** amount to be obtained */private double drawMoney; /*** Account */private Account a; ATM (double drawMoney, Account a) {super (); this. drawMoney = drawMoney; this. a = a;} public void run () {. draw (drawMoney) ;}} public class DrawMoneyDemo {public static void main (String [] args) {Account a = new Account (1000); ATM atm = new ATM (800, a); // get 800 yuan from account a // assume there are two threads simultaneously operating new Thread (atm, ""). start (); new Thread (atm, "B "). start ();}}
The execution result is:
A spit out 800.0 yuan
Your account don't have enough money!
For reentrant locks, the format is:
Public class X {private final ReentrantLock lock = new ReentrantLock (); // defines the method to ensure thread security public void m () {// lock. lock (); try {//... method body} finally {// release the lock in finally. unlock ();}}}
The ReentrantLock can be used to display locks and unlock locks. It has some basic behaviors and semantics similar to the implicit listener locks accessed by synchronized methods and statements, but is more powerful.