控制台程序。
当两个或多个线程共享同一资源时,例如文件或内存块,就需要采取措施,确保其中的一个线程不会修改另一个线程正在使用的资源。当其中的一个线程更新文件中的某个记录,同时另一个线程正在检索这个记录,就会出现灾难性的结果。管理这种情形的一种方式是对涉及的线程使用同步机制。
同步的目标是当多个线程希望访问同一资源时,确保在任意时刻只有一个线程可以访问。使用同步机制可以通过两种方式管理线程的执行:
1、可以在方法级别管理代码,这涉及方法的同步。
2、可以在块级别管理代码,这使用块的同步。
同步方法可以使任意类中方法的子集(或者所有的方法)都是互斥的,在任意时刻都只能执行其中的一个方法。使用synchronized关键字声明类中的方法,就可以把它们设置为互斥的。
1 // Define the bank 2 3 public class Bank { 4 // Perform a transaction 5 synchronized public void doTransaction(Transaction transaction) { 6 int balance = transaction.getAccount().getBalance(); // Get current balance 7 8 switch(transaction.getTransactionType()) { 9 case CREDIT: 10 // Credits require a lot of checks... 11 try { 12 Thread.sleep(100); 13 14 } catch(InterruptedException e) { 15 System.out.println(e); 16 } 17 balance += transaction.getAmount(); // Increment the balance 18 break; 19 20 case DEBIT: 21 // Debits require even more checks... 22 try { 23 Thread.sleep(150); 24 25 } catch(InterruptedException e) { 26 System.out.println(e); 27 } 28 balance -= transaction.getAmount(); // Decrement the balance 29 break; 30 31 default: // We should never get here 32 System.out.println("Invalid transaction"); 33 System.exit(1); 34 } 35 transaction.getAccount().setBalance(balance); // Restore the account balance 36 } 37 }
1 // Defines a customer account 2 public class Account { 3 // Constructor 4 public Account(int accountNumber, int balance) { 5 this.accountNumber = accountNumber; // Set the account number 6 this.balance = balance; // Set the initial balance 7 } 8 9 // Return the current balance 10 public int getBalance() { 11 return balance; 12 } 13 14 // Set the current balance 15 public void setBalance(int balance) { 16 this.balance = balance; 17 } 18 19 public int getAccountNumber() { 20 return accountNumber; 21 } 22 23 @Override 24 public String toString() { 25 return "A/C No. " + accountNumber + " : $" + balance; 26 } 27 28 private int balance; // The current account balance 29 private int accountNumber; // Identifies this account 30 }
1 // Bank account transaction types 2 public enum TransactionType {DEBIT, CREDIT }
1 public class Clerk implements Runnable { 2 // Constructor 3 public Clerk(Bank theBank) { 4 this.theBank = theBank; // Who the clerk works for 5 inTray = null; // No transaction initially 6 } 7 8 // Receive a transaction 9 public void doTransaction(Transaction transaction) { 10 inTray = transaction; 11 } 12 13 // The working clerk... 14 public void run() { 15 while(true) { // Non-stop work... 16 while(inTray == null) { // No transaction waiting? 17 try { 18 Thread.sleep(150); // Then take a break... 19 20 } catch(InterruptedException e) { 21 System.out.println(e); 22 } 23 } 24 25 theBank.doTransaction(inTray); 26 inTray = null; // In-tray is empty 27 } 28 } 29 30 // Busy check 31 public boolean isBusy() { 32 return inTray != null; // A full in-tray means busy! 33 } 34 35 private Bank theBank; // The employer - an electronic marvel 36 private Transaction inTray; // The in-tray holding a transaction 37 }
1 public class Transaction { 2 // Constructor 3 public Transaction(Account account, TransactionType type, int amount) { 4 this.account = account; 5 this.type = type; 6 this.amount = amount; 7 } 8 9 public Account getAccount() { 10 return account; 11 } 12 13 public TransactionType getTransactionType() { 14 return type; 15 } 16 17 public int getAmount() { 18 return amount; 19 } 20 @Override 21 public String toString() { 22 return type + " A//C: " + account + ": $" + amount; 23 } 24 25 private Account account; 26 private int amount; 27 private TransactionType type; 28 }
1 import java.util.Random; 2 3 public class BankOperation2 { 4 public static void main(String[] args) { 5 int initialBalance = 500; // The initial account balance 6 int totalCredits = 0; // Total credits on the account 7 int totalDebits =0; // Total debits on the account 8 int transactionCount = 20; // Number of debits and credits 9 10 // Create the account, the bank, and the clerks... 11 Bank theBank = new Bank(); // Create a bank 12 Clerk clerk1 = new Clerk(theBank); // Create the first clerk 13 Clerk clerk2 = new Clerk(theBank); // Create the second clerk 14 Account account = new Account(1, initialBalance); // Create an account 15 16 // Create the threads for the clerks as daemon, and start them off 17 Thread clerk1Thread = new Thread(clerk1); 18 Thread clerk2Thread = new Thread(clerk2); 19 clerk1Thread.setDaemon(true); // Set first as daemon 20 clerk2Thread.setDaemon(true); // Set second as daemon 21 clerk1Thread.start(); // Start the first 22 clerk2Thread.start(); // Start the second 23 24 // Generate transactions of each type and pass to the clerks 25 Random rand = new Random(); // Random number generator 26 Transaction transaction; // Stores a transaction 27 int amount = 0; // stores an amount of money 28 for(int i = 1 ; i <= transactionCount ; ++i) { 29 amount = 50 + rand.nextInt(26); // Generate amount of $50 to $75 30 transaction = new Transaction(account, // Account 31 TransactionType.CREDIT, // Credit transaction 32 amount); // of amount 33 totalCredits += amount; // Keep total credit tally 34 35 // Wait until the first clerk is free 36 while(clerk1.isBusy()) { 37 try { 38 Thread.sleep(25); // Busy so try later 39 40 } catch(InterruptedException e) { 41 System.out.println(e); 42 } 43 } 44 clerk1.doTransaction(transaction); // Now do the credit 45 46 amount = 30 + rand.nextInt(31); // Generate amount of $30 to $60 47 transaction = new Transaction(account, // Account 48 TransactionType.DEBIT, // Debit transaction 49 amount); // of amount 50 totalDebits += amount; // Keep total debit tally 51 // Wait until the second clerk is free 52 while(clerk2.isBusy()) { 53 try { 54 Thread.sleep(25); // Busy so try later 55 56 } catch(InterruptedException e) { 57 System.out.println(e); 58 } 59 } 60 clerk2.doTransaction(transaction); // Now do the debit 61 } 62 63 // Wait until both clerks are done 64 while(clerk1.isBusy() || clerk2.isBusy()) { 65 try { 66 Thread.sleep(25); 67 68 } catch(InterruptedException e) { 69 System.out.println(e); 70 } 71 } 72 73 // Now output the results 74 System.out.println( 75 "Original balance : $" + initialBalance+" " + 76 "Total credits : $" + totalCredits+" " + 77 "Total debits : $" + totalDebits+" " + 78 "Final balance : $" + account.getBalance() + " " + 79 "Should be : $" + (initialBalance + totalCredits - totalDebits)); 80 } 81 }
把处理账户的方法声明为synchronized,在其中一个职员对账户调用方法时,禁止另一个职员也调用同一个方法。
目前存在的问题是:银行的效率非常低,当其中一个职员在处理事物时,另一个职员却在闲着。