Java基础之线程——管理线程同步方法(BankOperation2)

控制台程序。

当两个或多个线程共享同一资源时,例如文件或内存块,就需要采取措施,确保其中的一个线程不会修改另一个线程正在使用的资源。当其中的一个线程更新文件中的某个记录,同时另一个线程正在检索这个记录,就会出现灾难性的结果。管理这种情形的一种方式是对涉及的线程使用同步机制。

同步的目标是当多个线程希望访问同一资源时,确保在任意时刻只有一个线程可以访问。使用同步机制可以通过两种方式管理线程的执行:

1、可以在方法级别管理代码,这涉及方法的同步。

2、可以在块级别管理代码,这使用块的同步。

同步方法可以使任意类中方法的子集(或者所有的方法)都是互斥的,在任意时刻都只能执行其中的一个方法。使用synchronized关键字声明类中的方法,就可以把它们设置为互斥的。

 // Define the bank

 public class Bank {
// Perform a transaction
synchronized public void doTransaction(Transaction transaction) {
int balance = transaction.getAccount().getBalance(); // Get current balance switch(transaction.getTransactionType()) {
case CREDIT:
// Credits require a lot of checks...
try {
Thread.sleep(100); } catch(InterruptedException e) {
System.out.println(e);
}
balance += transaction.getAmount(); // Increment the balance
break; case DEBIT:
// Debits require even more checks...
try {
Thread.sleep(150); } catch(InterruptedException e) {
System.out.println(e);
}
balance -= transaction.getAmount(); // Decrement the balance
break; default: // We should never get here
System.out.println("Invalid transaction");
System.exit(1);
}
transaction.getAccount().setBalance(balance); // Restore the account balance
}
}
 // Defines a customer account
public class Account {
// Constructor
public Account(int accountNumber, int balance) {
this.accountNumber = accountNumber; // Set the account number
this.balance = balance; // Set the initial balance
} // Return the current balance
public int getBalance() {
return balance;
} // Set the current balance
public void setBalance(int balance) {
this.balance = balance;
} public int getAccountNumber() {
return accountNumber;
} @Override
public String toString() {
return "A/C No. " + accountNumber + " : $" + balance;
} private int balance; // The current account balance
private int accountNumber; // Identifies this account
}
 // Bank account transaction types
public enum TransactionType {DEBIT, CREDIT }
 public class Clerk implements Runnable {
// Constructor
public Clerk(Bank theBank) {
this.theBank = theBank; // Who the clerk works for
inTray = null; // No transaction initially
} // Receive a transaction
public void doTransaction(Transaction transaction) {
inTray = transaction;
} // The working clerk...
public void run() {
while(true) { // Non-stop work...
while(inTray == null) { // No transaction waiting?
try {
Thread.sleep(150); // Then take a break... } catch(InterruptedException e) {
System.out.println(e);
}
} theBank.doTransaction(inTray);
inTray = null; // In-tray is empty
}
} // Busy check
public boolean isBusy() {
return inTray != null; // A full in-tray means busy!
} private Bank theBank; // The employer - an electronic marvel
private Transaction inTray; // The in-tray holding a transaction
}
 public class Transaction {
// Constructor
public Transaction(Account account, TransactionType type, int amount) {
this.account = account;
this.type = type;
this.amount = amount;
} public Account getAccount() {
return account;
} public TransactionType getTransactionType() {
return type;
} public int getAmount() {
return amount;
}
@Override
public String toString() {
return type + " A//C: " + account + ": $" + amount;
} private Account account;
private int amount;
private TransactionType type;
}
 import java.util.Random;

 public class BankOperation2 {
public static void main(String[] args) {
int initialBalance = 500; // The initial account balance
int totalCredits = 0; // Total credits on the account
int totalDebits =0; // Total debits on the account
int transactionCount = 20; // Number of debits and credits // Create the account, the bank, and the clerks...
Bank theBank = new Bank(); // Create a bank
Clerk clerk1 = new Clerk(theBank); // Create the first clerk
Clerk clerk2 = new Clerk(theBank); // Create the second clerk
Account account = new Account(1, initialBalance); // Create an account // Create the threads for the clerks as daemon, and start them off
Thread clerk1Thread = new Thread(clerk1);
Thread clerk2Thread = new Thread(clerk2);
clerk1Thread.setDaemon(true); // Set first as daemon
clerk2Thread.setDaemon(true); // Set second as daemon
clerk1Thread.start(); // Start the first
clerk2Thread.start(); // Start the second // Generate transactions of each type and pass to the clerks
Random rand = new Random(); // Random number generator
Transaction transaction; // Stores a transaction
int amount = 0; // stores an amount of money
for(int i = 1 ; i <= transactionCount ; ++i) {
amount = 50 + rand.nextInt(26); // Generate amount of $50 to $75
transaction = new Transaction(account, // Account
TransactionType.CREDIT, // Credit transaction
amount); // of amount
totalCredits += amount; // Keep total credit tally // Wait until the first clerk is free
while(clerk1.isBusy()) {
try {
Thread.sleep(25); // Busy so try later } catch(InterruptedException e) {
System.out.println(e);
}
}
clerk1.doTransaction(transaction); // Now do the credit amount = 30 + rand.nextInt(31); // Generate amount of $30 to $60
transaction = new Transaction(account, // Account
TransactionType.DEBIT, // Debit transaction
amount); // of amount
totalDebits += amount; // Keep total debit tally
// Wait until the second clerk is free
while(clerk2.isBusy()) {
try {
Thread.sleep(25); // Busy so try later } catch(InterruptedException e) {
System.out.println(e);
}
}
clerk2.doTransaction(transaction); // Now do the debit
} // Wait until both clerks are done
while(clerk1.isBusy() || clerk2.isBusy()) {
try {
Thread.sleep(25); } catch(InterruptedException e) {
System.out.println(e);
}
} // Now output the results
System.out.println(
"Original balance : $" + initialBalance+"\n" +
"Total credits : $" + totalCredits+"\n" +
"Total debits : $" + totalDebits+"\n" +
"Final balance : $" + account.getBalance() + "\n" +
"Should be : $" + (initialBalance + totalCredits - totalDebits));
}
}

把处理账户的方法声明为synchronized,在其中一个职员对账户调用方法时,禁止另一个职员也调用同一个方法。

目前存在的问题是:银行的效率非常低,当其中一个职员在处理事物时,另一个职员却在闲着。

上一篇:JavaScript 变量、类型与计算


下一篇:阿里云 virtual memory exhausted: 无法分配内存