本文介绍Java最基本的同步方式,即使用synchronized关键字来控制一个方法的并发访问,如果一个对象已用synchronized关键字声明,那么只有一个执行线程允许去访问它,其它试图访问这个对象的线程将被挂起,直到第一个线程访问完毕。
下面通过一个小例子来学习这个概念,公司向银行存钱,取钱场景。
1:创建Account的账号类,它是银行账户的模型,只有一个双精度浮点型属性,balance.
2:实现balance的get set 方法。
3:实现AddAmount()方法,将传入的数量加到余额balance中,并且在同一时间只允许一个线程去改变这个值,使用synchronized关键字。
4:实现SubtractAmount()方法,将传入的数量从余额balance中扣除,并且在同一时间只允许一个线程去改变这个值。
具体代码:
public class Account {
? ? /**
? ? * Balance of the bank account
? ? */
? ? private double balance;
? ? /**
? ? * Returns the balance of the account
? ? * @return the balance of the account
? ? */
? ? public double getBalance() {
? ? ? ? return balance;
? ? }
? ? /**
? ? * Establish the balance of the account
? ? * @param balance the new balance of the account
? ? */
? ? public void setBalance(double balance) {
? ? ? ? this.balance = balance;
? ? }
? ?
? ? /**
? ? * Add an import to the balance of the account
? ? * @param amount import to add to the balance
? ? */
? ? public synchronized void addAmount(double amount) {
? ? ? ? ? ? double tmp=balance;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? Thread.sleep(10);
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? ? ? tmp+=amount;
? ? }
? ?
? ? /**
? ? * Subtract an import to the balance of the account
? ? * @param amount import to subtract to the balance
? ? */
? ? public synchronized void subtractAmount(double amount) {
? ? ? ? ? ? double tmp=balance;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? Thread.sleep(10);
? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? ? ? tmp-=amount;
? ? ? ? ? ? balance=tmp;
? ? }
? ?
}
5:实现一个ATM模拟类Bank,它使用subtractAmount()方法对账户的余额进行扣除,实现Runabl接口。
具体代码:
public class Bank implements Runnable {
? ? /**
? ? * The account affected by the operations
? ? */
? ? private Account account;
? ?
? ? /**
? ? * Constructor of the class. Initializes the account
? ? * @param account The account affected by the operations
? ? */
? ? public Bank(Account account) {
? ? ? ? this.account=account;
? ? }
? ?
? ?
? ? /**
? ? * Core method of the Runnable
? ? */
? ? public void run() {
? ? ? ? for (int i=0; i<100; i++){
? ? ? ? ? ? account.subtractAmount(1000);
? ? ? ? }
? ? }
}
6:实现公司模拟类,调用addAmount()方法进行存钱,实现Runabl接口。
具体代码:
public class Company implements Runnable {
? ? /**
? ? * The account affected by the operations
? ? */
? ? private Account account;
? ?
? ? /**
? ? * Constructor of the class. Initializes the account
? ? * @param account the account affected by the operations
? ? */
? ? public Company(Account account) {
? ? ? ? this.account=account;
? ? }
? ?
? ? /**
? ? * Core method of the Runnable
? ? */
? ? public void run() {
? ? ? ? for (int i=0; i<100; i++){
? ? ? ? ? ? account.addAmount(1000);
? ? ? ? }
? ? }
7:在主方法中调用测试:通过线程的join方法,在存期那,取钱线程模拟完毕后打印出结构。
public class Main {
? ? /**
? ? * Main method of the example
? ? * @param args
? ? */
? ? public static void main(String[] args) {
? ? ? ? // Creates a new account ...
? ? ? ? Account? ? account=new Account();
? ? ? ? // an initialize its balance to 1000
? ? ? ? account.setBalance(1000);
? ? ? ?
? ? ? ? // Creates a new Company and a Thread to run its task
? ? ? ? Company? ? company=new Company(account);
? ? ? ? Thread companyThread=new Thread(company);
? ? ? ? // Creates a new Bank and a Thread to run its task
? ? ? ? Bank bank=new Bank(account);
? ? ? ? Thread bankThread=new Thread(bank);
? ? ? ?
? ? ? ? // Prints the initial balance
? ? ? ? System.out.printf("Account : Initial Balance: %f\n",account.getBalance());
? ? ? ?
? ? ? ? // Starts the Threads
? ? ? ? companyThread.start();
? ? ? ? bankThread.start();
? ? ? ? try {
? ? ? ? ? ? // Wait for the finalization of the Threads
? ? ? ? ? ? companyThread.join();
? ? ? ? ? ? bankThread.join();
? ? ? ? ? ? // Pr